• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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.AccessesPartialKey;
20 import com.google.crypto.tink.Key;
21 import com.google.crypto.tink.internal.OutputPrefixUtil;
22 import com.google.crypto.tink.util.Bytes;
23 import com.google.errorprone.annotations.CanIgnoreReturnValue;
24 import com.google.errorprone.annotations.RestrictedApi;
25 import java.math.BigInteger;
26 import java.security.GeneralSecurityException;
27 import java.util.Objects;
28 import javax.annotation.Nullable;
29 
30 /**
31  * Represents a public key for the RSA SSA PSS signature primitive.
32  *
33  * <p>Standard: https://www.rfc-editor.org/rfc/rfc8017.txt
34  */
35 public final class RsaSsaPssPublicKey extends SignaturePublicKey {
36   private final RsaSsaPssParameters parameters;
37   private final BigInteger modulus;
38   private final Bytes outputPrefix;
39   @Nullable private final Integer idRequirement;
40 
41   /** Builder for RsaSsaPssPublicKey. */
42   public static class Builder {
43     @Nullable private RsaSsaPssParameters parameters = null;
44     @Nullable private BigInteger modulus = null;
45     @Nullable private Integer idRequirement = null;
46 
Builder()47     private Builder() {}
48 
49     @CanIgnoreReturnValue
setParameters(RsaSsaPssParameters parameters)50     public Builder setParameters(RsaSsaPssParameters parameters) {
51       this.parameters = parameters;
52       return this;
53     }
54 
55     @CanIgnoreReturnValue
setModulus(BigInteger modulus)56     public Builder setModulus(BigInteger modulus) {
57       this.modulus = modulus;
58       return this;
59     }
60 
61     @CanIgnoreReturnValue
setIdRequirement(@ullable Integer idRequirement)62     public Builder setIdRequirement(@Nullable Integer idRequirement) {
63       this.idRequirement = idRequirement;
64       return this;
65     }
66 
getOutputPrefix()67     private Bytes getOutputPrefix() {
68       if (parameters.getVariant() == RsaSsaPssParameters.Variant.NO_PREFIX) {
69         return OutputPrefixUtil.EMPTY_PREFIX;
70       }
71       if (parameters.getVariant() == RsaSsaPssParameters.Variant.LEGACY
72           || parameters.getVariant() == RsaSsaPssParameters.Variant.CRUNCHY) {
73         return OutputPrefixUtil.getLegacyOutputPrefix(idRequirement);
74       }
75       if (parameters.getVariant() == RsaSsaPssParameters.Variant.TINK) {
76         return OutputPrefixUtil.getTinkOutputPrefix(idRequirement);
77       }
78       throw new IllegalStateException(
79           "Unknown RsaSsaPssParameters.Variant: " + parameters.getVariant());
80     }
81 
build()82     public RsaSsaPssPublicKey build() throws GeneralSecurityException {
83       if (parameters == null) {
84         throw new GeneralSecurityException("Cannot build without parameters");
85       }
86 
87       if (modulus == null) {
88         throw new GeneralSecurityException("Cannot build without modulus");
89       }
90 
91       int modulusSize = modulus.bitLength();
92       int paramModulusSize = parameters.getModulusSizeBits();
93       // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf, B.3 requires p and q
94       // to be chosen such that 2^(paramModulusSize-1) < modulus < 2^paramModulusSize.
95       if (modulusSize != paramModulusSize) {
96         throw new GeneralSecurityException(
97             "Got modulus size "
98                 + modulusSize
99                 + ", but parameters requires modulus size "
100                 + paramModulusSize);
101       }
102 
103       if (parameters.hasIdRequirement() && idRequirement == null) {
104         throw new GeneralSecurityException(
105             "Cannot create key without ID requirement with parameters with ID requirement");
106       }
107 
108       if (!parameters.hasIdRequirement() && idRequirement != null) {
109         throw new GeneralSecurityException(
110             "Cannot create key with ID requirement with parameters without ID requirement");
111       }
112       Bytes outputPrefix = getOutputPrefix();
113       return new RsaSsaPssPublicKey(parameters, modulus, outputPrefix, idRequirement);
114     }
115   }
116 
RsaSsaPssPublicKey( RsaSsaPssParameters parameters, BigInteger modulus, Bytes outputPrefix, @Nullable Integer idRequirement)117   private RsaSsaPssPublicKey(
118       RsaSsaPssParameters parameters,
119       BigInteger modulus,
120       Bytes outputPrefix,
121       @Nullable Integer idRequirement) {
122     this.parameters = parameters;
123     this.modulus = modulus;
124     this.outputPrefix = outputPrefix;
125     this.idRequirement = idRequirement;
126   }
127 
128   @RestrictedApi(
129       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
130       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
131       allowedOnPath = ".*Test\\.java",
132       allowlistAnnotations = {AccessesPartialKey.class})
builder()133   public static Builder builder() {
134     return new Builder();
135   }
136 
137   /** Returns the underlying key bytes. */
138   @RestrictedApi(
139       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
140       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
141       allowedOnPath = ".*Test\\.java",
142       allowlistAnnotations = {AccessesPartialKey.class})
getModulus()143   public BigInteger getModulus() {
144     return modulus;
145   }
146 
147   @Override
getOutputPrefix()148   public Bytes getOutputPrefix() {
149     return outputPrefix;
150   }
151 
152   @Override
getParameters()153   public RsaSsaPssParameters getParameters() {
154     return parameters;
155   }
156 
157   @Override
158   @Nullable
getIdRequirementOrNull()159   public Integer getIdRequirementOrNull() {
160     return idRequirement;
161   }
162 
163   @Override
equalsKey(Key o)164   public boolean equalsKey(Key o) {
165     if (!(o instanceof RsaSsaPssPublicKey)) {
166       return false;
167     }
168     RsaSsaPssPublicKey that = (RsaSsaPssPublicKey) o;
169     // Since outputPrefix is a function of parameters, we can ignore it here.
170     return that.parameters.equals(parameters)
171         && that.modulus.equals(modulus)
172         && Objects.equals(that.idRequirement, idRequirement);
173   }
174 }
175