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 static com.google.common.truth.Truth.assertThat; 20 import static com.google.crypto.tink.testing.TestUtil.assertExceptionContains; 21 import static java.nio.charset.StandardCharsets.UTF_8; 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertThrows; 24 import static org.junit.Assert.assertTrue; 25 26 import com.google.crypto.tink.config.TinkConfig; 27 import com.google.crypto.tink.internal.MonitoringAnnotations; 28 import com.google.crypto.tink.internal.MutableMonitoringRegistry; 29 import com.google.crypto.tink.internal.testing.FakeMonitoringClient; 30 import com.google.crypto.tink.proto.Keyset; 31 import java.io.ByteArrayInputStream; 32 import java.io.ByteArrayOutputStream; 33 import java.io.IOException; 34 import java.security.GeneralSecurityException; 35 import java.util.HashMap; 36 import java.util.List; 37 import java.util.Map; 38 import org.junit.BeforeClass; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 import org.junit.runners.JUnit4; 42 43 /** Tests for CleartextKeysetHandle. */ 44 @RunWith(JUnit4.class) 45 public class CleartextKeysetHandleTest { 46 @BeforeClass setUp()47 public static void setUp() throws GeneralSecurityException { 48 TinkConfig.register(); 49 } 50 51 @Test testParse()52 public void testParse() throws Exception { 53 // Create a keyset that contains a single HmacKey. 54 KeyTemplate template = KeyTemplates.get("HMAC_SHA256_128BITTAG"); 55 KeysetHandle handle = KeysetHandle.generateNew(template); 56 Keyset keyset = CleartextKeysetHandle.getKeyset(handle); 57 handle = CleartextKeysetHandle.parseFrom(keyset.toByteArray()); 58 assertEquals(keyset, handle.getKeyset()); 59 Object unused = handle.getPrimitive(RegistryConfiguration.get(), Mac.class); 60 } 61 62 @Test testRead()63 public void testRead() throws Exception { 64 // Create a keyset that contains a single HmacKey. 65 KeyTemplate template = KeyTemplates.get("HMAC_SHA256_128BITTAG"); 66 KeysetHandle handle = KeysetHandle.generateNew(template); 67 Keyset keyset1 = handle.getKeyset(); 68 69 KeysetHandle handle1 = 70 CleartextKeysetHandle.read(BinaryKeysetReader.withBytes(keyset1.toByteArray())); 71 assertEquals(keyset1, handle1.getKeyset()); 72 73 assertThat(handle1.size()).isEqualTo(1); 74 assertThat(handle1.getAt(0).getId()).isEqualTo(handle.getAt(0).getId()); 75 assertThat(handle1.getAt(0).getStatus()).isEqualTo(handle.getAt(0).getStatus()); 76 assertTrue(handle1.getAt(0).getKey().equalsKey(handle.getAt(0).getKey())); 77 } 78 79 @Test testWriteRead_samePrimitive()80 public void testWriteRead_samePrimitive() throws Exception { 81 // Create a keyset that contains a single HmacKey. 82 KeysetHandle handle = KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_128BITTAG")); 83 84 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 85 KeysetWriter writer = BinaryKeysetWriter.withOutputStream(outputStream); 86 CleartextKeysetHandle.write(handle, writer); 87 byte[] serializedKeyset = outputStream.toByteArray(); 88 89 ByteArrayInputStream inputStream1 = new ByteArrayInputStream(serializedKeyset); 90 KeysetReader reader1 = BinaryKeysetReader.withInputStream(inputStream1); 91 KeysetHandle readHandle1 = CleartextKeysetHandle.read(reader1); 92 93 ByteArrayInputStream inputStream2 = new ByteArrayInputStream(serializedKeyset); 94 KeysetReader reader2 = BinaryKeysetReader.withInputStream(inputStream2); 95 KeysetHandle readHandle2 = CleartextKeysetHandle.read(reader2, new HashMap<String, String>()); 96 97 // Check that the handle returned by CleartextKeysetHandle.read generates the same MAC. 98 Mac mac = handle.getPrimitive(RegistryConfiguration.get(), Mac.class); 99 Mac readMac1 = readHandle1.getPrimitive(RegistryConfiguration.get(), Mac.class); 100 Mac readMac2 = readHandle2.getPrimitive(RegistryConfiguration.get(), Mac.class); 101 byte[] data = "data".getBytes(UTF_8); 102 assertThat(readMac1.computeMac(data)).isEqualTo(mac.computeMac(data)); 103 assertThat(readMac2.computeMac(data)).isEqualTo(mac.computeMac(data)); 104 } 105 106 @Test testReadInvalidKeyset()107 public void testReadInvalidKeyset() throws Exception { 108 // Create a keyset that contains a single HmacKey. 109 KeyTemplate template = KeyTemplates.get("HMAC_SHA256_128BITTAG"); 110 Keyset keyset = KeysetHandle.generateNew(template).getKeyset(); 111 112 byte[] proto = keyset.toByteArray(); 113 proto[0] = (byte) ~proto[0]; 114 assertThrows( 115 IOException.class, 116 () -> { 117 KeysetHandle unused = CleartextKeysetHandle.read(BinaryKeysetReader.withBytes(proto)); 118 }); 119 assertThrows( 120 IOException.class, 121 () -> { 122 KeysetHandle unused = 123 CleartextKeysetHandle.read( 124 BinaryKeysetReader.withBytes(proto), new HashMap<String, String>()); 125 }); 126 } 127 128 @Test testVoidInputs()129 public void testVoidInputs() throws Exception { 130 GeneralSecurityException e = 131 assertThrows( 132 GeneralSecurityException.class, 133 () -> CleartextKeysetHandle.read(BinaryKeysetReader.withBytes(new byte[0]))); 134 assertExceptionContains(e, "empty keyset"); 135 136 GeneralSecurityException e2 = 137 assertThrows( 138 GeneralSecurityException.class, 139 () -> 140 CleartextKeysetHandle.read( 141 BinaryKeysetReader.withBytes(new byte[0]), new HashMap<String, String>())); 142 assertExceptionContains(e2, "empty keyset"); 143 144 GeneralSecurityException e3 = 145 assertThrows( 146 GeneralSecurityException.class, () -> CleartextKeysetHandle.parseFrom(new byte[0])); 147 assertExceptionContains(e3, "empty keyset"); 148 } 149 150 @Test testReadWithAnnotations_getLoggedByMonitoringClient()151 public void testReadWithAnnotations_getLoggedByMonitoringClient() throws Exception { 152 FakeMonitoringClient fakeMonitoringClient = new FakeMonitoringClient(); 153 MutableMonitoringRegistry.globalInstance().clear(); 154 MutableMonitoringRegistry.globalInstance().registerMonitoringClient(fakeMonitoringClient); 155 156 // Generate a serialized keyset 157 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 158 CleartextKeysetHandle.write( 159 KeysetHandle.generateNew(KeyTemplates.get("HMAC_SHA256_128BITTAG")), 160 BinaryKeysetWriter.withOutputStream(outputStream)); 161 byte[] serializedKeyset = outputStream.toByteArray(); 162 163 Map<String, String> annotations = new HashMap<>(); 164 annotations.put("annotation_name", "annotation_value"); 165 KeysetHandle handle = 166 CleartextKeysetHandle.read(BinaryKeysetReader.withBytes(serializedKeyset), annotations); 167 168 // Trigger monitoring event and verify that it gets logged with the annotations are set. 169 Mac mac = handle.getPrimitive(RegistryConfiguration.get(), Mac.class); 170 byte[] unused = mac.computeMac("data".getBytes(UTF_8)); 171 172 List<FakeMonitoringClient.LogEntry> logEntries = fakeMonitoringClient.getLogEntries(); 173 assertThat(logEntries).hasSize(1); 174 FakeMonitoringClient.LogEntry entry = logEntries.get(0); 175 MonitoringAnnotations expectedAnnotations = 176 MonitoringAnnotations.newBuilder().add("annotation_name", "annotation_value").build(); 177 assertThat(entry.getKeysetInfo().getAnnotations()).isEqualTo(expectedAnnotations); 178 } 179 } 180