• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 Google LLC
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.signature;
18 
19 import com.google.crypto.tink.CryptoFormat;
20 import com.google.crypto.tink.PublicKeyVerify;
21 import com.google.crypto.tink.internal.LegacyProtoKey;
22 import com.google.crypto.tink.internal.MonitoringClient;
23 import com.google.crypto.tink.internal.MonitoringKeysetInfo;
24 import com.google.crypto.tink.internal.MonitoringUtil;
25 import com.google.crypto.tink.internal.MutableMonitoringRegistry;
26 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
27 import com.google.crypto.tink.internal.PrimitiveConstructor;
28 import com.google.crypto.tink.internal.PrimitiveRegistry;
29 import com.google.crypto.tink.internal.PrimitiveSet;
30 import com.google.crypto.tink.internal.PrimitiveWrapper;
31 import com.google.crypto.tink.signature.internal.LegacyFullVerify;
32 import java.security.GeneralSecurityException;
33 import java.util.Arrays;
34 import java.util.List;
35 
36 /**
37  * The implementation of {@code PrimitiveWrapper<DeterministicAead>}.
38  *
39  * <p>The returned primitive works with a keyset (rather than a single key). To verify a signature,
40  * the primitive uses the prefix of the signature to efficiently select the right key in the set. If
41  * there is no key associated with the prefix or if the keys associated with the prefix do not work,
42  * the primitive tries all keys with {@link com.google.crypto.tink.proto.OutputPrefixType#RAW}.
43  *
44  * @since 1.0.0
45  */
46 public class PublicKeyVerifyWrapper implements PrimitiveWrapper<PublicKeyVerify, PublicKeyVerify> {
47 
48   private static final PublicKeyVerifyWrapper WRAPPER = new PublicKeyVerifyWrapper();
49   private static final PrimitiveConstructor<LegacyProtoKey, PublicKeyVerify>
50       LEGACY_PRIMITIVE_CONSTRUCTOR =
51           PrimitiveConstructor.create(
52               LegacyFullVerify::create, LegacyProtoKey.class, PublicKeyVerify.class);
53 
54   private static class WrappedPublicKeyVerify implements PublicKeyVerify {
55     private final PrimitiveSet<PublicKeyVerify> primitives;
56 
57     private final MonitoringClient.Logger monitoringLogger;
58 
WrappedPublicKeyVerify(PrimitiveSet<PublicKeyVerify> primitives)59     public WrappedPublicKeyVerify(PrimitiveSet<PublicKeyVerify> primitives) {
60       this.primitives = primitives;
61       if (primitives.hasAnnotations()) {
62         MonitoringClient client = MutableMonitoringRegistry.globalInstance().getMonitoringClient();
63         MonitoringKeysetInfo keysetInfo = MonitoringUtil.getMonitoringKeysetInfo(primitives);
64         this.monitoringLogger = client.createLogger(keysetInfo, "public_key_verify", "verify");
65       } else {
66         this.monitoringLogger = MonitoringUtil.DO_NOTHING_LOGGER;
67       }
68     }
69 
70     @Override
verify(final byte[] signature, final byte[] data)71     public void verify(final byte[] signature, final byte[] data) throws GeneralSecurityException {
72       if (signature.length <= CryptoFormat.NON_RAW_PREFIX_SIZE) {
73         // This also rejects raw signatures with size of 4 bytes or fewer. We're not aware of any
74         // schemes that output signatures that small.
75         monitoringLogger.logFailure();
76         throw new GeneralSecurityException("signature too short");
77       }
78       byte[] prefix = Arrays.copyOf(signature, CryptoFormat.NON_RAW_PREFIX_SIZE);
79       List<PrimitiveSet.Entry<PublicKeyVerify>> entries = primitives.getPrimitive(prefix);
80       for (PrimitiveSet.Entry<PublicKeyVerify> entry : entries) {
81         try {
82           entry.getFullPrimitive().verify(signature, data);
83           monitoringLogger.log(entry.getKeyId(), data.length);
84           // If there is no exception, the signature is valid and we can return.
85           return;
86         } catch (GeneralSecurityException e) {
87           // Ignored as we want to continue verification with the remaining keys.
88         }
89       }
90 
91       // None "non-raw" key matched, so let's try the raw keys (if any exist).
92       entries = primitives.getRawPrimitives();
93       for (PrimitiveSet.Entry<PublicKeyVerify> entry : entries) {
94         try {
95           entry.getFullPrimitive().verify(signature, data);
96           monitoringLogger.log(entry.getKeyId(), data.length);
97           // If there is no exception, the signature is valid and we can return.
98           return;
99         } catch (GeneralSecurityException e) {
100           // Ignored as we want to continue verification with raw keys.
101         }
102       }
103       // nothing works.
104       monitoringLogger.logFailure();
105       throw new GeneralSecurityException("invalid signature");
106     }
107   }
108 
109   @Override
wrap(final PrimitiveSet<PublicKeyVerify> primitives)110   public PublicKeyVerify wrap(final PrimitiveSet<PublicKeyVerify> primitives) {
111     return new WrappedPublicKeyVerify(primitives);
112   }
113 
114   @Override
getPrimitiveClass()115   public Class<PublicKeyVerify> getPrimitiveClass() {
116     return PublicKeyVerify.class;
117   }
118 
119   @Override
getInputPrimitiveClass()120   public Class<PublicKeyVerify> getInputPrimitiveClass() {
121     return PublicKeyVerify.class;
122   }
123 
124   /**
125    * Register the wrapper within the registry.
126    *
127    * <p>This is required for calls to {@link Keyset.getPrimitive} with a {@link PublicKeyVerify}
128    * argument.
129    */
register()130   static void register() throws GeneralSecurityException {
131     MutablePrimitiveRegistry.globalInstance().registerPrimitiveWrapper(WRAPPER);
132     MutablePrimitiveRegistry.globalInstance()
133         .registerPrimitiveConstructor(LEGACY_PRIMITIVE_CONSTRUCTOR);
134   }
135 
136   /**
137    * registerToInternalPrimitiveRegistry is a non-public method (it takes an argument of an
138    * internal-only type) registering an instance of {@code PublicKeyVerifyWrapper} to the provided
139    * {@code PrimitiveRegistry#Builder}.
140    */
registerToInternalPrimitiveRegistry( PrimitiveRegistry.Builder primitiveRegistryBuilder)141   public static void registerToInternalPrimitiveRegistry(
142       PrimitiveRegistry.Builder primitiveRegistryBuilder) throws GeneralSecurityException {
143     primitiveRegistryBuilder.registerPrimitiveWrapper(WRAPPER);
144   }
145 }
146