• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 
17 package com.google.crypto.tink;
18 
19 import java.security.GeneralSecurityException;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.ServiceLoader;
24 import java.util.concurrent.CopyOnWriteArrayList;
25 
26 /**
27  * A container for {@link KmsClient}-objects that are needed by {@link KeyManager}-objects for
28  * primitives that use KMS-managed keys.
29  *
30  * <p>This class consists exclusively of static methods that register and load {@link
31  * KmsClient}-objects.
32  *
33  * @since 1.0.0
34  */
35 public final class KmsClients {
36   // The list of KmsClients loaded automatically using ServiceLoader.
37   private static List<KmsClient> autoClients;
38 
39   private static final CopyOnWriteArrayList<KmsClient> clients = new CopyOnWriteArrayList<>();
40 
41   /**
42    * Adds a client to the list of known {@link KmsClient}-objects.
43    *
44    * <p>This function will always add the {@code client} to a global list. So this function should
45    * only be called on startup and not on every operation.
46    *
47    * <p>It is often not necessary to use this function. For example, you can call {@link
48    * KmsClient#getAead} to get a remote {@link Aead}. Use this {@link Aead} to encrypt a keyset with
49    * {@link TinkProtoKeysetFormat#serializeEncryptedKeyset}, or to create an envelope {@link Aead}
50    * using {@link com.google.crypto.tink.aead.KmsEnvelopeAead#create}.
51    */
add(KmsClient client)52   public static void add(KmsClient client) {
53     clients.add(client);
54   }
55 
56   /**
57    * Returns the first {@link KmsClient} registered with {@link KmsClients#add} that supports {@code
58    * keyUri}.
59    *
60    * @throws GeneralSecurityException if no KMS clients can be found that support {@code keyUri}
61    */
get(String keyUri)62   public static KmsClient get(String keyUri) throws GeneralSecurityException {
63     for (KmsClient client : clients) {
64       if (client.doesSupport(keyUri)) {
65         return client;
66       }
67     }
68     throw new GeneralSecurityException("No KMS client does support: " + keyUri);
69   }
70 
71   /**
72    * Returns the first {@link KmsClient} automatically loaded with {@link java.util.ServiceLoader}
73    * that supports {@code keyUri}.
74    *
75    * <p><b>Warning</b> This method searches over the classpath for all implementations of {@link
76    * KmsClient}. An attacker that can insert a class in your classpath (e.g., someone controlling a
77    * library that you're using) could provide a fake {@link KmsClient} that steal your keys. For
78    * this reason Tink does not use this method.
79    *
80    * @deprecated Don't use this.
81    * @throws GeneralSecurityException if cannot found any KMS clients that support {@code keyUri}
82    */
83   @Deprecated
getAutoLoaded(String keyUri)84   public static synchronized KmsClient getAutoLoaded(String keyUri)
85       throws GeneralSecurityException {
86     if (autoClients == null) {
87       autoClients = loadAutoKmsClients();
88     }
89     for (KmsClient client : autoClients) {
90       if (client.doesSupport(keyUri)) {
91         return client;
92       }
93     }
94     throw new GeneralSecurityException("No KMS client does support: " + keyUri);
95   }
96 
reset()97   static void reset() {
98     clients.clear();
99   }
100 
loadAutoKmsClients()101   private static List<KmsClient> loadAutoKmsClients() {
102     List<KmsClient> clients = new ArrayList<>();
103     ServiceLoader<KmsClient> clientLoader = ServiceLoader.load(KmsClient.class);
104     for (KmsClient element : clientLoader) {
105       clients.add(element);
106     }
107     return Collections.unmodifiableList(clients);
108   }
109 
KmsClients()110   private KmsClients() {}
111 }
112