1 // Copyright 2023 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.internal; 18 19 import com.google.crypto.tink.InsecureSecretKeyAccess; 20 import com.google.crypto.tink.Key; 21 import com.google.crypto.tink.KeyManager; 22 import com.google.crypto.tink.Parameters; 23 import com.google.crypto.tink.PrivateKey; 24 import com.google.crypto.tink.PrivateKeyManager; 25 import com.google.crypto.tink.proto.KeyData; 26 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 27 import com.google.crypto.tink.proto.KeyTemplate; 28 import com.google.crypto.tink.proto.OutputPrefixType; 29 import com.google.protobuf.ByteString; 30 import com.google.protobuf.ExtensionRegistryLite; 31 import com.google.protobuf.InvalidProtocolBufferException; 32 import com.google.protobuf.MessageLite; 33 import com.google.protobuf.Parser; 34 import java.security.GeneralSecurityException; 35 36 /** 37 * A composed KeyManager implements a KeyManager by accessing the internal specific registries. 38 * 39 * <p>Tink offers {@code Registry.getKeyManager} in the public API. While this shouldn't be used by 40 * users, we still want to be backwards compatible for users which use it. 41 * 42 * <p>In this class we use the global instances of the following classes to implement the KeyManager 43 * interface. 44 * 45 * <ul> 46 * <li>{@link MutableSerializationRegistry} 47 * <li>{@link MutablePrimitiveRegistry} 48 * <li>{@link MutableKeyCreationRegistry} 49 * </ul> 50 */ 51 public class LegacyKeyManagerImpl<P> implements KeyManager<P> { 52 final String typeUrl; 53 final Class<P> primitiveClass; 54 final KeyMaterialType keyMaterialType; 55 final Parser<? extends MessageLite> protobufKeyParser; 56 create( String typeUrl, Class<P> primitiveClass, KeyMaterialType keyMaterialType, Parser<? extends MessageLite> protobufKeyParser)57 public static <P> KeyManager<P> create( 58 String typeUrl, 59 Class<P> primitiveClass, 60 KeyMaterialType keyMaterialType, 61 Parser<? extends MessageLite> protobufKeyParser) { 62 return new LegacyKeyManagerImpl<>(typeUrl, primitiveClass, keyMaterialType, protobufKeyParser); 63 } 64 LegacyKeyManagerImpl( String typeUrl, Class<P> primitiveClass, KeyMaterialType keyMaterialType, Parser<? extends MessageLite> protobufKeyParser)65 LegacyKeyManagerImpl( 66 String typeUrl, 67 Class<P> primitiveClass, 68 KeyMaterialType keyMaterialType, 69 Parser<? extends MessageLite> protobufKeyParser) { 70 this.protobufKeyParser = protobufKeyParser; 71 this.typeUrl = typeUrl; 72 this.primitiveClass = primitiveClass; 73 this.keyMaterialType = keyMaterialType; 74 } 75 76 @Override getPrimitive(ByteString serializedKey)77 public P getPrimitive(ByteString serializedKey) throws GeneralSecurityException { 78 ProtoKeySerialization serialization = 79 ProtoKeySerialization.create( 80 typeUrl, serializedKey, keyMaterialType, OutputPrefixType.RAW, null); 81 Key key = 82 MutableSerializationRegistry.globalInstance() 83 .parseKey(serialization, InsecureSecretKeyAccess.get()); 84 return MutablePrimitiveRegistry.globalInstance().getPrimitive(key, primitiveClass); 85 } 86 87 @Override getPrimitive(MessageLite key)88 public final P getPrimitive(MessageLite key) throws GeneralSecurityException { 89 return getPrimitive(key.toByteString()); 90 } 91 92 @Override 93 @SuppressWarnings("UnusedException") newKey(ByteString serializedKeyFormat)94 public final MessageLite newKey(ByteString serializedKeyFormat) throws GeneralSecurityException { 95 KeyData keyData = newKeyData(serializedKeyFormat); 96 try { 97 return protobufKeyParser.parseFrom( 98 keyData.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 99 } catch (InvalidProtocolBufferException e) { 100 throw new GeneralSecurityException("Unexpectedly failed to parse key"); 101 } 102 } 103 104 @Override newKey(MessageLite keyFormat)105 public final MessageLite newKey(MessageLite keyFormat) throws GeneralSecurityException { 106 return newKey(keyFormat.toByteString()); 107 } 108 109 @Override doesSupport(String typeUrl)110 public final boolean doesSupport(String typeUrl) { 111 return typeUrl.equals(getKeyType()); 112 } 113 114 @Override getKeyType()115 public final String getKeyType() { 116 return typeUrl; 117 } 118 119 @Override getVersion()120 public int getVersion() { 121 return 0; 122 } 123 124 @Override newKeyData(ByteString serializedKeyFormat)125 public final KeyData newKeyData(ByteString serializedKeyFormat) throws GeneralSecurityException { 126 ProtoParametersSerialization parametersSerialization = 127 ProtoParametersSerialization.checkedCreate( 128 KeyTemplate.newBuilder() 129 .setTypeUrl(typeUrl) 130 .setValue(serializedKeyFormat) 131 .setOutputPrefixType(OutputPrefixType.RAW) 132 .build()); 133 Parameters parameters = 134 MutableSerializationRegistry.globalInstance().parseParameters(parametersSerialization); 135 Key key = 136 MutableKeyCreationRegistry.globalInstance() 137 .createKey(parameters, /* idRequirement= */ null); 138 ProtoKeySerialization keySerialization = 139 MutableSerializationRegistry.globalInstance() 140 .serializeKey(key, ProtoKeySerialization.class, InsecureSecretKeyAccess.get()); 141 return KeyData.newBuilder() 142 .setTypeUrl(keySerialization.getTypeUrl()) 143 .setValue(keySerialization.getValue()) 144 .setKeyMaterialType(keySerialization.getKeyMaterialType()) 145 .build(); 146 } 147 148 @Override getPrimitiveClass()149 public final Class<P> getPrimitiveClass() { 150 return primitiveClass; 151 } 152 153 private static class LegacyPrivateKeyManagerImpl<P> extends LegacyKeyManagerImpl<P> 154 implements PrivateKeyManager<P> { LegacyPrivateKeyManagerImpl( String typeUrl, Class<P> primitiveClass, Parser<? extends MessageLite> protobufKeyParser)155 protected LegacyPrivateKeyManagerImpl( 156 String typeUrl, Class<P> primitiveClass, Parser<? extends MessageLite> protobufKeyParser) { 157 super(typeUrl, primitiveClass, KeyMaterialType.ASYMMETRIC_PRIVATE, protobufKeyParser); 158 } 159 160 @Override getPublicKeyData(ByteString serializedKey)161 public KeyData getPublicKeyData(ByteString serializedKey) throws GeneralSecurityException { 162 ProtoKeySerialization serialization = 163 ProtoKeySerialization.create( 164 typeUrl, serializedKey, keyMaterialType, OutputPrefixType.RAW, null); 165 Key key = 166 MutableSerializationRegistry.globalInstance() 167 .parseKey(serialization, InsecureSecretKeyAccess.get()); 168 if (!(key instanceof PrivateKey)) { 169 throw new GeneralSecurityException("Key not private key"); 170 } 171 Key publicKey = ((PrivateKey) key).getPublicKey(); 172 ProtoKeySerialization publicKeySerialization = 173 MutableSerializationRegistry.globalInstance() 174 .serializeKey(publicKey, ProtoKeySerialization.class, InsecureSecretKeyAccess.get()); 175 return KeyData.newBuilder() 176 .setTypeUrl(publicKeySerialization.getTypeUrl()) 177 .setValue(publicKeySerialization.getValue()) 178 .setKeyMaterialType(publicKeySerialization.getKeyMaterialType()) 179 .build(); 180 } 181 } 182 createPrivateKeyManager( String typeUrl, Class<P> primitiveClass, Parser<? extends MessageLite> protobufKeyParser)183 public static <P> PrivateKeyManager<P> createPrivateKeyManager( 184 String typeUrl, Class<P> primitiveClass, Parser<? extends MessageLite> protobufKeyParser) { 185 return new LegacyPrivateKeyManagerImpl<P>(typeUrl, primitiveClass, protobufKeyParser); 186 } 187 } 188