• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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.jwt;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.assertThrows;
21 import static org.junit.Assert.assertTrue;
22 
23 import com.google.crypto.tink.InsecureSecretKeyAccess;
24 import com.google.crypto.tink.KeyTemplates;
25 import com.google.crypto.tink.KeysetHandle;
26 import com.google.crypto.tink.RegistryConfiguration;
27 import com.google.crypto.tink.TinkJsonProtoKeysetFormat;
28 import com.google.crypto.tink.TinkProtoKeysetFormat;
29 import com.google.crypto.tink.proto.KeyData;
30 import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
31 import com.google.crypto.tink.proto.KeyStatusType;
32 import com.google.crypto.tink.proto.Keyset;
33 import com.google.crypto.tink.subtle.Base64;
34 import com.google.crypto.tink.testing.TestUtil;
35 import com.google.crypto.tink.tinkkey.KeyAccess;
36 import com.google.gson.JsonArray;
37 import com.google.gson.JsonObject;
38 import com.google.gson.JsonParser;
39 import com.google.protobuf.ByteString;
40 import java.security.GeneralSecurityException;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.experimental.theories.DataPoints;
44 import org.junit.experimental.theories.FromDataPoints;
45 import org.junit.experimental.theories.Theories;
46 import org.junit.experimental.theories.Theory;
47 import org.junit.runner.RunWith;
48 
49 /** Unit tests for JwkSetConverter */
50 @RunWith(Theories.class)
51 public final class JwkSetConverterTest {
52 
53   @Before
setup()54   public void setup() throws Exception {
55     JwtSignatureConfig.register();
56   }
57 
58   private static final String ES256_KEYSET =
59       "{\"primaryKeyId\":282600252,\"key\":[{\"keyData\":{"
60           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\","
61           + "\"value\":\"EAEaIBDPI66hjLHvjxmUJ2nyHIBDmdOtQ4gPsvWgYYgZ0gygIiBTEK0rTACpAb97m+mvtJKAk0"
62           + "q3mHjPcUZm0C4EueDW4Q==\","
63           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
64           + "},\"status\":\"ENABLED\",\"keyId\":282600252,\"outputPrefixType\":\"RAW\"}]}";
65   private static final String ES256_JWK_SET =
66       "{\"keys\":[{"
67           + "\"kty\":\"EC\","
68           + "\"crv\":\"P-256\","
69           + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\","
70           + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\","
71           + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"]}]}";
72 
73   private static final String ES256_KEYSET_TINK =
74       "{\"primaryKeyId\":282600252,\"key\":[{\"keyData\":{"
75           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\","
76           + "\"value\":\"EAEaIBDPI66hjLHvjxmUJ2nyHIBDmdOtQ4gPsvWgYYgZ0gygIiBTEK0rTACpAb97m+mvtJKAk0"
77           + "q3mHjPcUZm0C4EueDW4Q==\","
78           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
79           + "},\"status\":\"ENABLED\",\"keyId\":282600252,\"outputPrefixType\":\"TINK\"}]}";
80   private static final String ES256_JWK_SET_KID =
81       "{\"keys\":[{"
82           + "\"kty\":\"EC\","
83           + "\"crv\":\"P-256\","
84           + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\","
85           + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\","
86           + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"],"
87           + "\"kid\":\"ENgjPA\"}]}";
88   private static final String ES256_JWK_SET_KID_TINK =
89       "{\"primaryKeyId\":1623060913,\"key\":[{\"keyData\":{"
90           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\","
91           + "\"value\":\"EAEaIQAQzyOuoYyx748ZlCdp8hyAQ5nTrUOID7L1oGGIGdIMoCIhAFMQrStMAKkBv3ub6a+0ko"
92           + "CTSreYeM9xRmbQLgS54NbhKggKBkVOZ2pQQQ==\","
93           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"},"
94           + "\"status\":\"ENABLED\",\"keyId\":1623060913,\"outputPrefixType\":\"RAW\"}]}";
95 
96   private static final String ES384_KEYSET =
97       "{\"primaryKeyId\":456087424,\"key\":[{\"keyData\":{"
98           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\","
99           + "\"value\":\"EAIaMQDSjvWihoKGmr4nlDuI/KkvuPvEZr+B4bU0MuXQQXgyNMGApFm2iTeotv7LCSsG3mQiME"
100           + "HIMGx4wa+Y8yeJQWMiSpukpPM7jP9GqaykZQQ2GY/NLg/n9+BJtntgvFhG5gWLTg==\","
101           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
102           + "},\"status\":\"ENABLED\",\"keyId\":456087424,\"outputPrefixType\":\"RAW\"}]}";
103   private static final String ES384_JWK_SET =
104       "{\"keys\":[{\"kty\":\"EC\",\"crv\":\"P-384\","
105           + "\"x\":\"0o71ooaChpq-J5Q7iPypL7j7xGa_geG1NDLl0EF4MjTBgKRZtok3qLb-ywkrBt5k\","
106           + "\"y\":\"QcgwbHjBr5jzJ4lBYyJKm6Sk8zuM_0aprKRlBDYZj80uD-f34Em2e2C8WEbmBYtO\","
107           + "\"use\":\"sig\",\"alg\":\"ES384\",\"key_ops\":[\"verify\"]}]}";
108 
109   private static final String ES512_KEYSET =
110       "{\"primaryKeyId\":1570200439,\"key\":[{\"keyData\":{"
111           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\","
112           + "\"value\":\"EAMaQgEV3nweRej6Z1/aPTqCkc1tQla5eVI68+qfwR1kB/wXCuYCB5otarhomUt64Fah/8Tjf0"
113           + "WJHMZyFr86RUitiRQm1SJCATht/NOX8RcbaEr1MaH+0BFTaepvpTzSfQ04C2P8VCoURB3GeVKk4VQh8O/KLSYf"
114           + "X+58bqEnaZ0G7W9qjHa2ols2\","
115           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
116           + "},\"status\":\"ENABLED\",\"keyId\":1570200439,\"outputPrefixType\":\"RAW\"}]}";
117   private static final String ES512_JWK_SET =
118       "{\"keys\":[{\"kty\":\"EC\",\"crv\":\"P-521\","
119           + "\"x\":\"ARXefB5F6PpnX9o9OoKRzW1CVrl5Ujrz6p_BHWQH_BcK5gIHmi1quGiZS3rgVqH_xON_RYkcxnIWvzpFSK2JFCbV\","
120           + "\"y\":\"ATht_NOX8RcbaEr1MaH-0BFTaepvpTzSfQ04C2P8VCoURB3GeVKk4VQh8O_KLSYfX-58bqEnaZ0G7W9qjHa2ols2\","
121           + "\"use\":\"sig\",\"alg\":\"ES512\",\"key_ops\":[\"verify\"]}]}";
122 
123   private static final String RS256_KEYSET =
124       "{\"primaryKeyId\":482168993,\"key\":[{\"keyData\":{"
125           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\","
126           + "\"value\":\"EAEagQIAkspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwf"
127           + "GMClfe/alIs2GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI+5hZ6ifUsv8W8mSHKlsVMmvOf"
128           + "C2P5+l72qTwN6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B/n7nfiWw9YN5++pfwyoitzoMoVKOOpj7fF"
129           + "q88f8ArpC7kR1SBTe20Bt1AmpZDT2Dmfmlb/Q1UFjj/F3C77NCNQ344ZcAEI42HY+uighy5GdKQRHMoTT1OzyD"
130           + "G90ABjggQqDGW+zXzyIDAQAB\","
131           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
132           + "},\"status\":\"ENABLED\",\"keyId\":482168993,\"outputPrefixType\":\"RAW\"}]}";
133   //
134   private static final String RS256_JWK_SET =
135       "{\"keys\":[{\"kty\":\"RSA\","
136           + "\"n\":\"kspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwfGMClfe_alIs2"
137           + "GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI-5hZ6ifUsv8W8mSHKlsVMmvOfC2P5-l72qTwN"
138           + "6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B_n7nfiWw9YN5--pfwyoitzoMoVKOOpj7fFq88f8ArpC7kR"
139           + "1SBTe20Bt1AmpZDT2Dmfmlb_Q1UFjj_F3C77NCNQ344ZcAEI42HY-uighy5GdKQRHMoTT1OzyDG90ABjggQqDG"
140           + "W-zXzw\","
141           + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}";
142 
143   private static final String RS256_KEYSET_TINK =
144       "{\"primaryKeyId\":482168993,\"key\":[{\"keyData\":{"
145           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\","
146           + "\"value\":\"EAEagQIAkspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwf"
147           + "GMClfe/alIs2GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI+5hZ6ifUsv8W8mSHKlsVMmvOf"
148           + "C2P5+l72qTwN6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B/n7nfiWw9YN5++pfwyoitzoMoVKOOpj7fF"
149           + "q88f8ArpC7kR1SBTe20Bt1AmpZDT2Dmfmlb/Q1UFjj/F3C77NCNQ344ZcAEI42HY+uighy5GdKQRHMoTT1OzyD"
150           + "G90ABjggQqDGW+zXzyIDAQAB\","
151           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
152           + "},\"status\":\"ENABLED\",\"keyId\":482168993,\"outputPrefixType\":\"TINK\"}]}";
153   private static final String RS256_JWK_SET_KID =
154       "{\"keys\":[{\"kty\":\"RSA\","
155           + "\"n\":\"kspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwfGMClfe_alIs2"
156           + "GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI-5hZ6ifUsv8W8mSHKlsVMmvOfC2P5-l72qTwN"
157           + "6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B_n7nfiWw9YN5--pfwyoitzoMoVKOOpj7fFq88f8ArpC7kR"
158           + "1SBTe20Bt1AmpZDT2Dmfmlb_Q1UFjj_F3C77NCNQ344ZcAEI42HY-uighy5GdKQRHMoTT1OzyDG90ABjggQqDG"
159           + "W-zXzw\","
160           + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"],"
161           + "\"kid\":\"HL1QoQ\"}]}";
162   private static final String RS256_JWK_SET_KID_TINK =
163       "{\"primaryKeyId\":1204986267,\"key\":[{\"keyData\":{"
164           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\","
165           + "\"value\":\"EAEagQIAkspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwf"
166           + "GMClfe/alIs2GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI+5hZ6ifUsv8W8mSHKlsVMmvOf"
167           + "C2P5+l72qTwN6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B/n7nfiWw9YN5++pfwyoitzoMoVKOOpj7fF"
168           + "q88f8ArpC7kR1SBTe20Bt1AmpZDT2Dmfmlb/Q1UFjj/F3C77NCNQ344ZcAEI42HY+uighy5GdKQRHMoTT1OzyD"
169           + "G90ABjggQqDGW+zXzyIDAQABKggKBkhMMVFvUQ==\","
170           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"},"
171           + "\"status\":\"ENABLED\",\"keyId\":1204986267,\"outputPrefixType\":\"RAW\"}]}";
172 
173   private static final String RS384_KEYSET =
174       "{\"primaryKeyId\":333504275,\"key\":[{\"keyData\":{"
175           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\","
176           + "\"value\":\"EAIagQMAnlBY5WD7gVQjNKvrS2whLKzt0Eql72B6haZ17eKifNn4S49eGdBy9RLj/mvHXAbacr"
177           + "ngt9fzi0iv/WQ57jUmtO1b/wLt5LYk9APsBYjywDCIe+u9UouikP7c3SBqjjQijZ50jgYbMY6cL7s2Gx5lI1vl"
178           + "GX3ZExLVYbNoI9VBFAWjSDefd6GugESxXQFnnO3p2GHOKryZLeDH/KzVacTq2/pVXKVH/9/EQzcLB0oYUljZ4v"
179           + "YQ4HCAcwnUZbirsRwA0350Dz0Mlj+3+9sSAF8FPA+F/wlIBkPqjJ26b80V5FU4mBTzvYoXGTjkD7+bxH9p28hu"
180           + "JSU96P4WdG5PYVwI1VEYwGipkUIpMWjJ7dXAtmltHzM9vkUt2bsBe9vyJjmRXyoC6mHSJbSyOm9Dd8BENobcUL"
181           + "9h+aBoxruY+mU49kAHzzeAntn8C+vIrxN+X6N2EU9N8t9BF+mwYiBEsY54wx99RbRrY9yICfPBmQJGwXSxNCXB"
182           + "RrbJyxkIVuqvACP5IgMBAAE=\","
183           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
184           + "},\"status\":\"ENABLED\",\"keyId\":333504275,\"outputPrefixType\":\"RAW\"}]}";
185   private static final String RS384_JWK_SET =
186       "{\"keys\":[{\"kty\":\"RSA\","
187           + "\"n\":\"nlBY5WD7gVQjNKvrS2whLKzt0Eql72B6haZ17eKifNn4S49eGdBy9RLj_mvHXAbacrngt9fzi0iv_W"
188           + "Q57jUmtO1b_wLt5LYk9APsBYjywDCIe-u9UouikP7c3SBqjjQijZ50jgYbMY6cL7s2Gx5lI1vlGX3ZExLVYbNo"
189           + "I9VBFAWjSDefd6GugESxXQFnnO3p2GHOKryZLeDH_KzVacTq2_pVXKVH_9_EQzcLB0oYUljZ4vYQ4HCAcwnUZb"
190           + "irsRwA0350Dz0Mlj-3-9sSAF8FPA-F_wlIBkPqjJ26b80V5FU4mBTzvYoXGTjkD7-bxH9p28huJSU96P4WdG5P"
191           + "YVwI1VEYwGipkUIpMWjJ7dXAtmltHzM9vkUt2bsBe9vyJjmRXyoC6mHSJbSyOm9Dd8BENobcUL9h-aBoxruY-m"
192           + "U49kAHzzeAntn8C-vIrxN-X6N2EU9N8t9BF-mwYiBEsY54wx99RbRrY9yICfPBmQJGwXSxNCXBRrbJyxkIVuqv"
193           + "ACP5\","
194           + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS384\",\"key_ops\":[\"verify\"]}]}";
195 
196   private static final String RS512_KEYSET =
197       "{\"primaryKeyId\":705596479,\"key\":[{\"keyData\":{"
198           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\","
199           + "\"value\":\"EAMagQQAkKxZ9IRzF56gh47RXLJzQ6lffcnBmQSwvxUDJ0wHpKZzfAawOn1uidbgEoQ3XWOgtN"
200           + "vi7QeKLE4GjQa5bY0xdRnu8nKjFcsvH+eu1sV8oVoZ984J5mT1mhwU6nt26p4xKyeapMhzYYNvKudQjQJ8SbpV"
201           + "OFpEiJ7j0ECMUd4Q8mCUqWsrXYE8+1CcHjprsIxdot+haCARc72RBj9cLuBIhJNzlFXNmsYh8yoSiEYr/auRvg"
202           + "/kIlNlnlOK/rJM/jMXbB6FuWdePrtqZ+ce2TVyARqjZJ0G0vZcPuvOhgS4LM7/Aeal84ZhIcHladSo/g8pK1eU"
203           + "hnRqRXJpsltwux+1XVJeg2a0FQ0BN3Ft25uu5jhfvGWXeTkQOR7LbpbxKTI+vumSy9dmY4UrgAG37N8Xj5/Neq"
204           + "BT51L3qE6tk2ZLoO7yjRjhADK5lnbb4iYWWvWd3kqyv0JVlxfDzjAaYtiduEUIdCe45MGk8DpCn9Lnjlunhm4Q"
205           + "yQufK8k8UPiBbWNEODI8pjTSEjs0wyMqhegBKAvtVEhr029bg3Lv7YjN9FDvx4usuWGc16bXkTqNgCK4KzPG7P"
206           + "wV120r6IVGflfpSkd5rrkzDY01fsP0mW57QCHA67bxqLUECr2dAfNzz6ddS9pqXQyXZWCyWKcvTFsGrr1oECwD"
207           + "OmW+nUIHGklr9Q0iAwEAAQ==\","
208           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
209           + "},\"status\":\"ENABLED\",\"keyId\":705596479,\"outputPrefixType\":\"RAW\"}]}";
210   private static final String RS512_JWK_SET =
211       "{\"keys\":[{\"kty\":\"RSA\","
212           + "\"n\":\"kKxZ9IRzF56gh47RXLJzQ6lffcnBmQSwvxUDJ0wHpKZzfAawOn1uidbgEoQ3XWOgtNvi7QeKLE4GjQ"
213           + "a5bY0xdRnu8nKjFcsvH-eu1sV8oVoZ984J5mT1mhwU6nt26p4xKyeapMhzYYNvKudQjQJ8SbpVOFpEiJ7j0ECM"
214           + "Ud4Q8mCUqWsrXYE8-1CcHjprsIxdot-haCARc72RBj9cLuBIhJNzlFXNmsYh8yoSiEYr_auRvg_kIlNlnlOK_r"
215           + "JM_jMXbB6FuWdePrtqZ-ce2TVyARqjZJ0G0vZcPuvOhgS4LM7_Aeal84ZhIcHladSo_g8pK1eUhnRqRXJpsltw"
216           + "ux-1XVJeg2a0FQ0BN3Ft25uu5jhfvGWXeTkQOR7LbpbxKTI-vumSy9dmY4UrgAG37N8Xj5_NeqBT51L3qE6tk2"
217           + "ZLoO7yjRjhADK5lnbb4iYWWvWd3kqyv0JVlxfDzjAaYtiduEUIdCe45MGk8DpCn9Lnjlunhm4QyQufK8k8UPiB"
218           + "bWNEODI8pjTSEjs0wyMqhegBKAvtVEhr029bg3Lv7YjN9FDvx4usuWGc16bXkTqNgCK4KzPG7PwV120r6IVGfl"
219           + "fpSkd5rrkzDY01fsP0mW57QCHA67bxqLUECr2dAfNzz6ddS9pqXQyXZWCyWKcvTFsGrr1oECwDOmW-nUIHGklr"
220           + "9Q0\","
221           + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS512\",\"key_ops\":[\"verify\"]}]}";
222 
223   private static final String PS256_KEYSET =
224       "{\"primaryKeyId\":1508587714,\"key\":[{\"keyData\":{"
225           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\","
226           + "\"value\":\"EAEagQMAj7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d+Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1"
227           + "TMmksY2Ugf/7+Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz+9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed+TLIlgvw"
228           + "uSTF4B5d6QkZWBymq7My6vV+epzWnoLpVDzCHh+c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDg"
229           + "wQ63rVCo2eWDS/BYK4rG22luSTDVfQVHU1NXlwXEnb/eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy"
230           + "3XiSeCGtghBXLMf/ge113Q9WDJ+RN1Xa4vgHJCO0+VO+cAugVkiu9UgsPP8o/r7tA2aP/Ps8EHYa1IaZg75vnr"
231           + "MZPvsTH7WG2SjSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX/PN6DLKoK2PaT0I+iLK9mRi1Z4OjFbl9KA"
232           + "ZXXElhAQTzrEI2adIgMBAAE=\","
233           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
234           + "},\"status\":\"ENABLED\",\"keyId\":1508587714,\"outputPrefixType\":\"RAW\"}]}";
235 
236   private static final String PS256_JWK_SET =
237       "{\"keys\":[{\"kty\":\"RSA\","
238           + "\"n\":\"j7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d-Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1TMmksY2Ugf_7"
239           + "-Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz-9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed-TLIlgvwuSTF4B5d6QkZ"
240           + "WBymq7My6vV-epzWnoLpVDzCHh-c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDgwQ63rVCo2eWD"
241           + "S_BYK4rG22luSTDVfQVHU1NXlwXEnb_eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy3XiSeCGtghBX"
242           + "LMf_ge113Q9WDJ-RN1Xa4vgHJCO0-VO-cAugVkiu9UgsPP8o_r7tA2aP_Ps8EHYa1IaZg75vnrMZPvsTH7WG2S"
243           + "jSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX_PN6DLKoK2PaT0I-iLK9mRi1Z4OjFbl9KAZXXElhAQTzrE"
244           + "I2ad\","
245           + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"PS256\",\"key_ops\":[\"verify\"]}]}";
246 
247   private static final String PS256_KEYSET_TINK =
248       "{\"primaryKeyId\":1508587714,\"key\":[{\"keyData\":{"
249           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\","
250           + "\"value\":\"EAEagQMAj7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d+Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1"
251           + "TMmksY2Ugf/7+Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz+9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed+TLIlgvw"
252           + "uSTF4B5d6QkZWBymq7My6vV+epzWnoLpVDzCHh+c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDg"
253           + "wQ63rVCo2eWDS/BYK4rG22luSTDVfQVHU1NXlwXEnb/eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy"
254           + "3XiSeCGtghBXLMf/ge113Q9WDJ+RN1Xa4vgHJCO0+VO+cAugVkiu9UgsPP8o/r7tA2aP/Ps8EHYa1IaZg75vnr"
255           + "MZPvsTH7WG2SjSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX/PN6DLKoK2PaT0I+iLK9mRi1Z4OjFbl9KA"
256           + "ZXXElhAQTzrEI2adIgMBAAE=\","
257           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
258           + "},\"status\":\"ENABLED\",\"keyId\":1508587714,\"outputPrefixType\":\"TINK\"}]}";
259   private static final String PS256_JWK_SET_KID =
260       "{\"keys\":[{\"kty\":\"RSA\","
261           + "\"n\":\"j7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d-Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1TMmksY2Ugf_7"
262           + "-Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz-9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed-TLIlgvwuSTF4B5d6QkZ"
263           + "WBymq7My6vV-epzWnoLpVDzCHh-c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDgwQ63rVCo2eWD"
264           + "S_BYK4rG22luSTDVfQVHU1NXlwXEnb_eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy3XiSeCGtghBX"
265           + "LMf_ge113Q9WDJ-RN1Xa4vgHJCO0-VO-cAugVkiu9UgsPP8o_r7tA2aP_Ps8EHYa1IaZg75vnrMZPvsTH7WG2S"
266           + "jSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX_PN6DLKoK2PaT0I-iLK9mRi1Z4OjFbl9KAZXXElhAQTzrE"
267           + "I2ad\","
268           + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"PS256\",\"key_ops\":[\"verify\"],"
269           + "\"kid\":\"Wes4wg\"}]}";
270   private static final String PS256_JWK_SET_KID_TINK =
271       "{\"primaryKeyId\":1004877962,\"key\":[{\"keyData\":{"
272           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\","
273           + "\"value\":\"EAEagQMAj7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d+Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1"
274           + "TMmksY2Ugf/7+Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz+9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed+TLIlgvw"
275           + "uSTF4B5d6QkZWBymq7My6vV+epzWnoLpVDzCHh+c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDg"
276           + "wQ63rVCo2eWDS/BYK4rG22luSTDVfQVHU1NXlwXEnb/eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy"
277           + "3XiSeCGtghBXLMf/ge113Q9WDJ+RN1Xa4vgHJCO0+VO+cAugVkiu9UgsPP8o/r7tA2aP/Ps8EHYa1IaZg75vnr"
278           + "MZPvsTH7WG2SjSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX/PN6DLKoK2PaT0I+iLK9mRi1Z4OjFbl9KA"
279           + "ZXXElhAQTzrEI2adIgMBAAEqCAoGV2VzNHdn\","
280           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"},"
281           + "\"status\":\"ENABLED\",\"keyId\":1004877962,\"outputPrefixType\":\"RAW\"}]}";
282 
283   private static final String PS384_KEYSET =
284       "{\"primaryKeyId\":1042230435,\"key\":[{\"keyData\":{"
285           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\","
286           + "\"value\":\"EAIagQMAv6a0OergWYmY1k6l6vx6Of5+RxCeeQ9jMTXQyvO0GCgMDExxtqVS8S25ehZ5LNDIiG"
287           + "jhE3v2++D7QEjnzOC5UqI1ZwPxUBSrOaf5oDbJ9vBc2c7wDyJhRV8UobQSpzunD4kXypVhytjwRdiP61vG0C/e"
288           + "L0x+LijtM/XVee1Y+5mWrypVrB6EHKtdkMx2WIYNpsFOForFrr6JzLbWfDRWoqbCXKYivnw+CSE38ddW1XsrAT"
289           + "76E2Vf+womuwyBbkjLaiWvNxNFBTap2IaBLKAni6x7pqYCeu1n9eMUi41oz9QM8xfOvpH+wubc2PjwyTsb1FDT"
290           + "LnhV36tQLTVGdQdCDMF2Z8Agrnio3n1SFjSbYgFyVtpCwFKM2Z0zfO7k9jVbYYkzglzkJfp/lQrsuWqe4CVJjF"
291           + "E1H4BxcU7L0j8755kGJI08h1b7LPgqJcPgtHjcqbxHFU2yOf7mNGlW7YTnoQBO0StzQUk7kEw3X0+niEwX/L8j"
292           + "qW4YMbxrGdAfkTnPIgMBAAE=\","
293           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
294           + "},\"status\":\"ENABLED\",\"keyId\":1042230435,\"outputPrefixType\":\"RAW\"}]}";
295 
296   private static final String PS384_JWK_SET =
297       "{\"keys\":[{\"kty\":\"RSA\","
298           + "\"n\":\"v6a0OergWYmY1k6l6vx6Of5-RxCeeQ9jMTXQyvO0GCgMDExxtqVS8S25ehZ5LNDIiGjhE3v2--D7QE"
299           + "jnzOC5UqI1ZwPxUBSrOaf5oDbJ9vBc2c7wDyJhRV8UobQSpzunD4kXypVhytjwRdiP61vG0C_eL0x-LijtM_XV"
300           + "ee1Y-5mWrypVrB6EHKtdkMx2WIYNpsFOForFrr6JzLbWfDRWoqbCXKYivnw-CSE38ddW1XsrAT76E2Vf-womuw"
301           + "yBbkjLaiWvNxNFBTap2IaBLKAni6x7pqYCeu1n9eMUi41oz9QM8xfOvpH-wubc2PjwyTsb1FDTLnhV36tQLTVG"
302           + "dQdCDMF2Z8Agrnio3n1SFjSbYgFyVtpCwFKM2Z0zfO7k9jVbYYkzglzkJfp_lQrsuWqe4CVJjFE1H4BxcU7L0j"
303           + "8755kGJI08h1b7LPgqJcPgtHjcqbxHFU2yOf7mNGlW7YTnoQBO0StzQUk7kEw3X0-niEwX_L8jqW4YMbxrGdAf"
304           + "kTnP\","
305           + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"PS384\",\"key_ops\":[\"verify\"]}]}";
306 
307   private static final String PS512_KEYSET =
308       "{\"primaryKeyId\":257081135,\"key\":[{\"keyData\":{"
309           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\","
310           + "\"value\":\"EAMagQQAnOUQvBwNRgeI3zlzIhVo4NzFVCsQn9hd2EIclz6cWBRMFr4EX5lXLK0StSIB7EQP4c"
311           + "iHa+vr59sOgMFMC2kiXRUXNtl99QhGwH0YjbWeDC50PKEAjH1hhhPgSw2dFcUVs4jbScDrwNn1sQ8rkgSNczvQ"
312           + "NpV1MtBhS/CC1PxVF88JaejG2zr+unoFlw7xnqxBWMzNrMHZHwqga2vL3inSbvA/RGQjnE2DzQSwZkXthGSwYB"
313           + "jOYbGawMN4onkAx/myHMyTg/TLAqG9GUyB0DVelvVoGZG/QJBY2Fp2FlpOQRKeBr6pC7Lk8zZL4GJk264KoOpG"
314           + "8v1t7PveN+STIdTE2D548K+GDOvsvrO4ZhofS/iqN9xLucuU1HkqKUqyLvMxsWum8Zhp7zinFdBnDOgeheOHUg"
315           + "N/iwjupk6u1Svt+RWNJsfb2l0jrvzf0cRMbPeLZRmpDwBxBvXWo61u6uaBEVb+ooZ6K5+hx3Rld7wXktjYIZzH"
316           + "qUr39P5yTw28b8Y2dPFWR4vwr2/0zBxcDmTRRtQ7vPOtZPD0/LVIXkgbBiLILpycnucWt9Lq9Hc62KFiTQOAuu"
317           + "Oxz7ObBegXjnFupiZZ9PyzO5WgT9lRpH7U7tzGLAjV+AUpjH6HA1o6bRLKOHFBPS+I9IqAYb/RpF6M/6hCmC2R"
318           + "z64yYzR3y4vHKGMiAwEAAQ==\","
319           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
320           + "},\"status\":\"ENABLED\",\"keyId\":257081135,\"outputPrefixType\":\"RAW\"}]}";
321 
322   private static final String PS512_JWK_SET =
323       "{\"keys\":[{\"kty\":\"RSA\","
324           + "\"n\":\"nOUQvBwNRgeI3zlzIhVo4NzFVCsQn9hd2EIclz6cWBRMFr4EX5lXLK0StSIB7EQP4ciHa-vr59sOgM"
325           + "FMC2kiXRUXNtl99QhGwH0YjbWeDC50PKEAjH1hhhPgSw2dFcUVs4jbScDrwNn1sQ8rkgSNczvQNpV1MtBhS_CC"
326           + "1PxVF88JaejG2zr-unoFlw7xnqxBWMzNrMHZHwqga2vL3inSbvA_RGQjnE2DzQSwZkXthGSwYBjOYbGawMN4on"
327           + "kAx_myHMyTg_TLAqG9GUyB0DVelvVoGZG_QJBY2Fp2FlpOQRKeBr6pC7Lk8zZL4GJk264KoOpG8v1t7PveN-ST"
328           + "IdTE2D548K-GDOvsvrO4ZhofS_iqN9xLucuU1HkqKUqyLvMxsWum8Zhp7zinFdBnDOgeheOHUgN_iwjupk6u1S"
329           + "vt-RWNJsfb2l0jrvzf0cRMbPeLZRmpDwBxBvXWo61u6uaBEVb-ooZ6K5-hx3Rld7wXktjYIZzHqUr39P5yTw28"
330           + "b8Y2dPFWR4vwr2_0zBxcDmTRRtQ7vPOtZPD0_LVIXkgbBiLILpycnucWt9Lq9Hc62KFiTQOAuuOxz7ObBegXjn"
331           + "FupiZZ9PyzO5WgT9lRpH7U7tzGLAjV-AUpjH6HA1o6bRLKOHFBPS-I9IqAYb_RpF6M_6hCmC2Rz64yYzR3y4vH"
332           + "KGM\","
333           + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"PS512\",\"key_ops\":[\"verify\"]}]}";
334 
335   private static final String P256_PUBLIC_KEYSET_SMALL_COORDINATES =
336       "{\"primaryKeyId\":2124611562,\"key\":[{\"keyData\":{\"typeUrl\":"
337           + " \"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\""
338           + " ,\"value\":\"EAEaH2lFjtbwLgtzRDh7dV9sYmW4IWl3ZKA+WghvrQPiCNoiIEJ8pQXMy"
339           + " A/JywaGWT+IHmWxuVYWqdxkPsUSHLhSQm51\",\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"}"
340           + " ,\"status\":\"ENABLED\",\"keyId\":2124611562,\"outputPrefixType\":\"TINK\"}]}";
341   private static final String P384_PUBLIC_KEYSET_SMALL_COORDINATES =
342       "{\"primaryKeyId\":4159170178,\"key\":[{\"keyData\":{"
343           + " \"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\","
344           + " \"value\":\"EAIaL/bm1+e6X7gat+MJK3e65BGlZzKIf6I1q0Ro8zAKeyryUxgvZl8Ww/NlcVN2XJhEI"
345           + " jA3b73hm8eDfSEEUAAaJbrLZFOFGnSdTWng116r+hOvszYiov+WrsTyIgnL/9aRdN8=\","
346           + " \"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"},\"status\":\"ENABLED\","
347           + " \"keyId\":4159170178,\"outputPrefixType\":\"TINK\"}]}";
348   private static final String P521_PUBLIC_KEYSET_SMALL_COORDINATES =
349       "{\"primaryKeyId\":1286030637,\"key\":[{\"keyData\":{"
350           + " \"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\","
351           + " \"value\":\"EAMaQUgdEssWf+tdFT3vSoy/OAotV501af+XQ6JSXDjnOPCzZnFh8fYwrJ8Yu8XYF3"
352           + " 3IeHBdAIKyicKuW884JkjYR1qJIkH2OWoa4SOmk0FtpeRBZHPbs7U8SMFXVkaV+HZtjmfl11QGiQU9hqU"
353           + " hoW9ock2K0xg6wdcWBe67YTVFdQbThFmtCg==\",\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"},"
354           + " \"status\":\"ENABLED\",\"keyId\":1286030637,\"outputPrefixType\":\"TINK\"}]}";
355 
356   private static final String PRIVATEKEY_KEYSET =
357       "{\"primaryKeyId\":152493399,\"key\":[{\"keyData\":{"
358           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPrivateKey\","
359           + "\"value\":\"EkYQARogaHkaakArEB51RyZ236S5x3BxaNTFycWuXIGZF8adZ2UiIFlZT7MFogZ8ARbS1URIAP"
360           + "cpw8A0g2uwAHRkBqGUiCU2GiBI4jtU/59Zajohgeezi2BXB13O8IJh8V3b0itq5zyy5Q==\","
361           + "\"keyMaterialType\":\"ASYMMETRIC_PRIVATE\""
362           + "},\"status\":\"ENABLED\",\"keyId\":152493399,\"outputPrefixType\":\"RAW\"}]}";
363 
364   private static final String KEYSET_WITH_TWO_KEYS =
365       "{\"primaryKeyId\":282600252,\"key\":["
366           + "{\"keyData\":{"
367           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\","
368           + "\"value\":\"EAEaIBDPI66hjLHvjxmUJ2nyHIBDmdOtQ4gPsvWgYYgZ0gygIiBTEK0rTACpAb97m+mvtJKAk0"
369           + "q3mHjPcUZm0C4EueDW4Q==\","
370           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
371           + "},\"status\":\"ENABLED\",\"keyId\":282600252,\"outputPrefixType\":\"RAW\"},"
372           + "{\"keyData\":{"
373           + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\","
374           + "\"value\":\"EAEagQIAkspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwf"
375           + "GMClfe/alIs2GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI+5hZ6ifUsv8W8mSHKlsVMmvOf"
376           + "C2P5+l72qTwN6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B/n7nfiWw9YN5++pfwyoitzoMoVKOOpj7fF"
377           + "q88f8ArpC7kR1SBTe20Bt1AmpZDT2Dmfmlb/Q1UFjj/F3C77NCNQ344ZcAEI42HY+uighy5GdKQRHMoTT1OzyD"
378           + "G90ABjggQqDGW+zXzyIDAQAB\","
379           + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\""
380           + "},\"status\":\"ENABLED\",\"keyId\":482168993,\"outputPrefixType\":\"RAW\"}]}";
381   private static final String JWK_SET_WITH_TWO_KEYS =
382       "{\"keys\":[{"
383           + "\"kty\":\"EC\","
384           + "\"crv\":\"P-256\","
385           + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\","
386           + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\","
387           + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"]},"
388           + "{\"kty\":\"RSA\","
389           + "\"n\":\"kspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwfGMClfe_alIs2"
390           + "GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI-5hZ6ifUsv8W8mSHKlsVMmvOfC2P5-l72qTwN"
391           + "6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B_n7nfiWw9YN5--pfwyoitzoMoVKOOpj7fFq88f8ArpC7kR"
392           + "1SBTe20Bt1AmpZDT2Dmfmlb_Q1UFjj_F3C77NCNQ344ZcAEI42HY-uighy5GdKQRHMoTT1OzyDG90ABjggQqDG"
393           + "W-zXzw\","
394           + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}";
395 
assertEqualJwkSets(String jwkSet1, String jwkSet2)396   private static void assertEqualJwkSets(String jwkSet1, String jwkSet2) throws Exception {
397     // Consider these strings equal, if their equal after parsing them.
398     // The keys may have any order.
399     JsonObject parsedjwkSet1 = JsonParser.parseString(jwkSet1).getAsJsonObject();
400     JsonObject parsedjwkSet2 = JsonParser.parseString(jwkSet2).getAsJsonObject();
401     JsonArray keys1 = parsedjwkSet1.remove("keys").getAsJsonArray();
402     JsonArray keys2 = parsedjwkSet2.remove("keys").getAsJsonArray();
403     assertThat(keys1).containsExactlyElementsIn(keys2);
404     assertThat(parsedjwkSet1).isEqualTo(parsedjwkSet2);
405   }
406 
407   @Test
assertEqualJwkSets_equal()408   public void assertEqualJwkSets_equal() throws Exception {
409     // Whitespace, order of object properties, and order of keys is ignored.
410     assertEqualJwkSets(
411         "{\"keys\":[{\"kty\": \"EC\"},     {\"e\":\"f\",\"kty\": \"RSA\"}]}",
412         "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"f\"}, {\"kty\":\"EC\"}]}");
413   }
414 
415   @Test
assertEqualJwkSets_notEequal()416   public void assertEqualJwkSets_notEequal() throws Exception {
417     // Order of arrays (except "keys" array) is not ignored.
418     assertThrows(
419         AssertionError.class,
420         () ->
421             assertEqualJwkSets(
422                 "{\"keys\":[{\"kty\":\"EC\",\"key_ops\":[\"b\",\"c\"]}]}",
423                 "{\"keys\":[{\"kty\":\"EC\",\"key_ops\":[\"c\",\"b\"]}]}"));
424   }
425 
convertToJwkSet(String jsonKeyset)426   private static String convertToJwkSet(String jsonKeyset) throws Exception {
427     KeysetHandle handle =
428         TinkJsonProtoKeysetFormat.parseKeyset(jsonKeyset, InsecureSecretKeyAccess.get());
429     return JwkSetConverter.fromPublicKeysetHandle(handle);
430   }
431 
getCoordinate(JsonObject jwkSet, String coordinate)432   private static byte[] getCoordinate(JsonObject jwkSet, String coordinate) throws Exception {
433     return Base64.urlSafeDecode(
434         jwkSet.get("keys").getAsJsonArray().get(0).getAsJsonObject().get(coordinate).getAsString());
435   }
436 
437   @Test
convertEcdsaKeysets_encodesFixedSizeCordinates()438   public void convertEcdsaKeysets_encodesFixedSizeCordinates() throws Exception {
439     JsonObject jwkSet =
440         JsonParser.parseString(convertToJwkSet(P256_PUBLIC_KEYSET_SMALL_COORDINATES))
441             .getAsJsonObject();
442     assertThat(getCoordinate(jwkSet, "x")).hasLength(32);
443     assertThat(getCoordinate(jwkSet, "y")).hasLength(32);
444     jwkSet =
445         JsonParser.parseString(convertToJwkSet(P384_PUBLIC_KEYSET_SMALL_COORDINATES))
446             .getAsJsonObject();
447     assertThat(getCoordinate(jwkSet, "x")).hasLength(48);
448     assertThat(getCoordinate(jwkSet, "y")).hasLength(48);
449     jwkSet =
450         JsonParser.parseString(convertToJwkSet(P521_PUBLIC_KEYSET_SMALL_COORDINATES))
451             .getAsJsonObject();
452     assertThat(getCoordinate(jwkSet, "x")).hasLength(66);
453     assertThat(getCoordinate(jwkSet, "y")).hasLength(66);
454   }
455 
456   @Test
convertEcdsaKeysets_success()457   public void convertEcdsaKeysets_success() throws Exception {
458     assertEqualJwkSets(convertToJwkSet(ES256_KEYSET), ES256_JWK_SET);
459     assertEqualJwkSets(convertToJwkSet(ES384_KEYSET), ES384_JWK_SET);
460     assertEqualJwkSets(convertToJwkSet(ES512_KEYSET), ES512_JWK_SET);
461     assertEqualJwkSets(convertToJwkSet(ES256_KEYSET_TINK), ES256_JWK_SET_KID);
462   }
463 
464   @Test
convertRsaSsaPkcs1Keysets_success()465   public void convertRsaSsaPkcs1Keysets_success() throws Exception {
466     assertEqualJwkSets(convertToJwkSet(RS256_KEYSET), RS256_JWK_SET);
467     assertEqualJwkSets(convertToJwkSet(RS384_KEYSET), RS384_JWK_SET);
468     assertEqualJwkSets(convertToJwkSet(RS512_KEYSET), RS512_JWK_SET);
469     assertEqualJwkSets(convertToJwkSet(RS256_KEYSET_TINK), RS256_JWK_SET_KID);
470   }
471 
472   @Test
convertRsaSsaPssKeysets_success()473   public void convertRsaSsaPssKeysets_success() throws Exception {
474     assertEqualJwkSets(convertToJwkSet(PS256_KEYSET), PS256_JWK_SET);
475     assertEqualJwkSets(convertToJwkSet(PS384_KEYSET), PS384_JWK_SET);
476     assertEqualJwkSets(convertToJwkSet(PS512_KEYSET), PS512_JWK_SET);
477     assertEqualJwkSets(convertToJwkSet(PS256_KEYSET_TINK), PS256_JWK_SET_KID);
478   }
479 
480   @Test
toPublicKeysetHandlefromPublicKeysetHandle_success()481   public void toPublicKeysetHandlefromPublicKeysetHandle_success() throws Exception {
482     assertEqualJwkSets(
483         JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(ES256_JWK_SET)),
484         ES256_JWK_SET);
485     assertEqualJwkSets(
486         JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(ES384_JWK_SET)),
487         ES384_JWK_SET);
488     assertEqualJwkSets(
489         JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(ES512_JWK_SET)),
490         ES512_JWK_SET);
491     assertEqualJwkSets(
492         JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(RS256_JWK_SET)),
493         RS256_JWK_SET);
494     assertEqualJwkSets(
495         JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(RS384_JWK_SET)),
496         RS384_JWK_SET);
497     assertEqualJwkSets(
498         JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(RS512_JWK_SET)),
499         RS512_JWK_SET);
500     assertEqualJwkSets(
501         JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(PS256_JWK_SET)),
502         PS256_JWK_SET);
503     assertEqualJwkSets(
504         JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(PS384_JWK_SET)),
505         PS384_JWK_SET);
506     assertEqualJwkSets(
507         JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(PS512_JWK_SET)),
508         PS512_JWK_SET);
509   }
510 
511   @Test
toPublicKeysetHandleWithValidKid_fromPublicKeysetHandle_sameJwkSet()512   public void toPublicKeysetHandleWithValidKid_fromPublicKeysetHandle_sameJwkSet()
513       throws Exception {
514     // When the kid can be decoded into a key ID, the output prefix type of the key will be TINK,
515     // and the same kid value will be generated again when converted to JWK Set.
516     assertEqualJwkSets(
517         JwkSetConverter.fromPublicKeysetHandle(
518             JwkSetConverter.toPublicKeysetHandle(ES256_JWK_SET_KID)),
519         ES256_JWK_SET_KID);
520     assertEqualJwkSets(
521         JwkSetConverter.fromPublicKeysetHandle(
522             JwkSetConverter.toPublicKeysetHandle(RS256_JWK_SET_KID)),
523         RS256_JWK_SET_KID);
524     assertEqualJwkSets(
525         JwkSetConverter.fromPublicKeysetHandle(
526             JwkSetConverter.toPublicKeysetHandle(PS256_JWK_SET_KID)),
527         PS256_JWK_SET_KID);
528   }
529 
530   @Test
jwkEs256WithKid_isImportedAsRaw()531   public void jwkEs256WithKid_isImportedAsRaw() throws Exception {
532     KeysetHandle converted = JwkSetConverter.toPublicKeysetHandle(ES256_JWK_SET_KID);
533     KeysetHandle expected =
534         TinkJsonProtoKeysetFormat.parseKeyset(
535             ES256_JWK_SET_KID_TINK, InsecureSecretKeyAccess.get());
536     // The KeyID is picked at random, hence we just compare the keys.
537     assertTrue(converted.getAt(0).getKey().equalsKey(expected.getAt(0).getKey()));
538   }
539 
540   @Test
jwkRs256WithKid_isImportedAsRaw()541   public void jwkRs256WithKid_isImportedAsRaw() throws Exception {
542     KeysetHandle converted = JwkSetConverter.toPublicKeysetHandle(RS256_JWK_SET_KID);
543     KeysetHandle expected =
544         TinkJsonProtoKeysetFormat.parseKeyset(
545             RS256_JWK_SET_KID_TINK, InsecureSecretKeyAccess.get());
546     // The KeyID is picked at random, hence we just compare the keys.
547     assertTrue(converted.getAt(0).getKey().equalsKey(expected.getAt(0).getKey()));
548   }
549 
550   @Test
jwkPs256WithKid_isImportedAsRaw()551   public void jwkPs256WithKid_isImportedAsRaw() throws Exception {
552     KeysetHandle converted = JwkSetConverter.toPublicKeysetHandle(PS256_JWK_SET_KID);
553     KeysetHandle expected =
554         TinkJsonProtoKeysetFormat.parseKeyset(
555             PS256_JWK_SET_KID_TINK, InsecureSecretKeyAccess.get());
556     // The KeyID is picked at random, hence we just compare the keys.
557     assertTrue(converted.getAt(0).getKey().equalsKey(expected.getAt(0).getKey()));
558   }
559 
560   @Test
jwkWithEmptyKid_kidIsPreserved()561   public void jwkWithEmptyKid_kidIsPreserved() throws Exception {
562     String esWithEmptyKid = ES256_JWK_SET_KID.replace("\"ENgjPA\"", "\"\"");
563     assertEqualJwkSets(
564         JwkSetConverter.fromPublicKeysetHandle(
565             JwkSetConverter.toPublicKeysetHandle(esWithEmptyKid)),
566         esWithEmptyKid);
567     String rsWithEmptyKid = RS256_JWK_SET_KID.replace("\"HL1QoQ\"", "\"\"");
568     assertEqualJwkSets(
569         JwkSetConverter.fromPublicKeysetHandle(
570             JwkSetConverter.toPublicKeysetHandle(rsWithEmptyKid)),
571         rsWithEmptyKid);
572     String psWithEmptyKid = PS256_JWK_SET_KID.replace("\"Wes4wg\"", "\"\"");
573     assertEqualJwkSets(
574         JwkSetConverter.fromPublicKeysetHandle(
575             JwkSetConverter.toPublicKeysetHandle(psWithEmptyKid)),
576         psWithEmptyKid);
577   }
578 
579   @Test
toPublicKeysetHandleSetsKeyIdsAndPrimaryKeyId()580   public void toPublicKeysetHandleSetsKeyIdsAndPrimaryKeyId() throws Exception {
581     KeysetHandle handle = JwkSetConverter.toPublicKeysetHandle(JWK_SET_WITH_TWO_KEYS);
582     assertThat(handle.size()).isEqualTo(2);
583     assertThat(handle.getAt(0).getKey()).isInstanceOf(JwtEcdsaPublicKey.class);
584     assertThat(handle.getAt(1).getKey()).isInstanceOf(JwtRsaSsaPkcs1PublicKey.class);
585   }
586 
587   @DataPoints("templatesNames")
588   public static final String[] TEMPLATE_NAMES =
589       new String[] {
590         "JWT_ES256",
591         "JWT_ES384",
592         "JWT_ES512",
593         "JWT_ES256_RAW",
594         "JWT_RS256_2048_F4",
595         "JWT_RS256_3072_F4",
596         "JWT_RS384_3072_F4",
597         "JWT_RS512_4096_F4",
598         "JWT_RS256_2048_F4_RAW",
599         "JWT_PS256_2048_F4",
600         "JWT_PS256_3072_F4",
601         "JWT_PS384_3072_F4",
602         "JWT_PS512_4096_F4",
603         "JWT_PS256_2048_F4_RAW",
604       };
605 
606   @Theory
convertTinkToJwksTokenVerification_success( @romDataPoints"templatesNames") String templateName)607   public void convertTinkToJwksTokenVerification_success(
608       @FromDataPoints("templatesNames") String templateName) throws Exception {
609     if (TestUtil.isTsan()) {
610       // KeysetHandle.generateNew is too slow in Tsan.
611       return;
612     }
613     KeysetHandle keysetHandle = KeysetHandle.generateNew(KeyTemplates.get(templateName));
614 
615     String jwksString =
616         JwkSetConverter.fromPublicKeysetHandle(keysetHandle.getPublicKeysetHandle());
617 
618     KeysetHandle publicKeysetHandle = JwkSetConverter.toPublicKeysetHandle(jwksString);
619 
620     JwtPublicKeySign signer =
621         keysetHandle.getPrimitive(RegistryConfiguration.get(), JwtPublicKeySign.class);
622     JwtPublicKeyVerify verifier =
623         publicKeysetHandle.getPrimitive(RegistryConfiguration.get(), JwtPublicKeyVerify.class);
624 
625     RawJwt rawToken = RawJwt.newBuilder().setJwtId("jwtId").withoutExpiration().build();
626     String signedCompact = signer.signAndEncode(rawToken);
627     JwtValidator validator = JwtValidator.newBuilder().allowMissingExpiration().build();
628     VerifiedJwt verifiedToken = verifier.verifyAndDecode(signedCompact, validator);
629     assertThat(verifiedToken.getJwtId()).isEqualTo("jwtId");
630   }
631 
632   @Test
keysetWithTwoKeys_fromPublicKeysetHandleSuccess()633   public void keysetWithTwoKeys_fromPublicKeysetHandleSuccess() throws Exception {
634     assertEqualJwkSets(convertToJwkSet(KEYSET_WITH_TWO_KEYS), JWK_SET_WITH_TWO_KEYS);
635   }
636 
637   @Test
primaryKeyIdMissing_fromPublicKeysetHandleSuccess()638   public void primaryKeyIdMissing_fromPublicKeysetHandleSuccess() throws Exception {
639     String keyset = ES256_KEYSET.replace("\"primaryKeyId\":282600252,", "");
640     assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset));
641   }
642 
643   @Test
legacyEcdsaKeysets_fromPublicKeysetHandleFails()644   public void legacyEcdsaKeysets_fromPublicKeysetHandleFails() throws Exception {
645     String keyset = ES256_KEYSET.replace("RAW", "LEGACY");
646     assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset));
647   }
648 
649   @Test
crunchyEcdsaKeysets_fromPublicKeysetHandleFails()650   public void crunchyEcdsaKeysets_fromPublicKeysetHandleFails() throws Exception {
651     String keyset = ES256_KEYSET.replace("RAW", "CRUNCHY");
652     assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset));
653   }
654 
655   @Test
privateKey_fromPublicKeysetHandleFails()656   public void privateKey_fromPublicKeysetHandleFails() throws Exception {
657     assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(PRIVATEKEY_KEYSET));
658   }
659 
660   @Test
legacyRsaSsaPkcs1Keysets_fromPublicKeysetHandleFails()661   public void legacyRsaSsaPkcs1Keysets_fromPublicKeysetHandleFails() throws Exception {
662     String keyset = RS256_KEYSET.replace("RAW", "LEGACY");
663     assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset));
664   }
665 
666   @Test
crunchyRsaSsaPkcs1Keysets_fromPublicKeysetHandleFails()667   public void crunchyRsaSsaPkcs1Keysets_fromPublicKeysetHandleFails() throws Exception {
668     String keyset = RS256_KEYSET.replace("RAW", "CRUNCHY");
669     assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset));
670   }
671 
672   @Test
legacyRsaSsaPssKeysets_fromPublicKeysetHandleFails()673   public void legacyRsaSsaPssKeysets_fromPublicKeysetHandleFails() throws Exception {
674     String keyset = PS256_KEYSET.replace("RAW", "LEGACY");
675     assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset));
676   }
677 
678   @Test
crunchyRsaSsaPssKeysets_fromPublicKeysetHandleFails()679   public void crunchyRsaSsaPssKeysets_fromPublicKeysetHandleFails() throws Exception {
680     String keyset = PS256_KEYSET.replace("RAW", "CRUNCHY");
681     assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset));
682   }
683 
684   @Test
fromPublicKeysetHandle_throwsOnInvalidKeysetHandle()685   public void fromPublicKeysetHandle_throwsOnInvalidKeysetHandle() throws Exception {
686     Keyset keyset =
687         Keyset.newBuilder()
688             .setPrimaryKeyId(1)
689             .addKey(
690                 Keyset.Key.newBuilder()
691                     .setKeyId(1)
692                     // Keysets with unknown status are not parsed properly and will throw unchecked
693                     // at getAt()
694                     .setStatus(KeyStatusType.UNKNOWN_STATUS)
695                     .setKeyData(
696                         KeyData.newBuilder()
697                             .setTypeUrl("somenonexistenttypeurl")
698                             .setKeyMaterialType(KeyMaterialType.ASYMMETRIC_PUBLIC)
699                             .setValue(ByteString.EMPTY)))
700             .build();
701     KeysetHandle handle = TinkProtoKeysetFormat.parseKeysetWithoutSecret(keyset.toByteArray());
702     assertThrows(
703         GeneralSecurityException.class, () -> JwkSetConverter.fromPublicKeysetHandle(handle));
704   }
705 
706   @Test
ecdsaWithoutUseAndKeyOps_toPublicKeysetHandleSuccess()707   public void ecdsaWithoutUseAndKeyOps_toPublicKeysetHandleSuccess() throws Exception {
708     String jwksString =
709         "{"
710             + "\"keys\":[{"
711             + "\"kty\":\"EC\","
712             + "\"crv\":\"P-256\","
713             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
714             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
715             + "\"alg\":\"ES256\""
716             + "}]}";
717     // ignore returned value, we only test that it worked.
718     Object unused = JwkSetConverter.toPublicKeysetHandle(jwksString);
719   }
720 
721   @Test
ecdsaPrivateKey_fails()722   public void ecdsaPrivateKey_fails() throws Exception {
723     // Example from https://datatracker.ietf.org/doc/html/rfc7517#appendix-A.2
724     String jwksString =
725         "{"
726             + "\"keys\":[{"
727             + "\"kty\":\"EC\","
728             + "\"crv\":\"P-256\","
729             + "\"x\":\"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4\","
730             + "\"y\":\"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM\","
731             + "\"d\":\"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE\","
732             + "\"alg\":\"ES256\""
733             + "}]}";
734     assertThrows(
735         UnsupportedOperationException.class,
736         () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
737   }
738 
739   @Test
ecdsaWithUnknownField_toPublicKeysetHandleSuccess()740   public void ecdsaWithUnknownField_toPublicKeysetHandleSuccess() throws Exception {
741     String jwksString =
742         "{"
743             + "\"keys\":[{"
744             + "\"kty\":\"EC\","
745             + "\"crv\":\"P-256\","
746             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
747             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
748             + "\"alg\":\"ES256\","
749             + "\"unknown\":1234,"
750             + "\"use\":\"sig\","
751             + "\"key_ops\":[\"verify\"]"
752             + "}]}";
753     // ignore returned value, we only test that it worked.
754     Object unused = JwkSetConverter.toPublicKeysetHandle(jwksString);
755   }
756 
757   @Test
ecdsaWithoutAlg_toPublicKeysetHandleFails()758   public void ecdsaWithoutAlg_toPublicKeysetHandleFails() throws Exception {
759     String jwksString =
760         "{"
761             + "\"keys\":[{"
762             + "\"kty\":\"EC\","
763             + "\"crv\":\"P-256\","
764             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
765             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
766             + "\"use\":\"sig\","
767             + "\"key_ops\":[\"verify\"]"
768             + "}]}";
769     assertThrows(
770         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
771   }
772 
773   @Test
ecdsaWithoutKty_toPublicKeysetHandleFails()774   public void ecdsaWithoutKty_toPublicKeysetHandleFails() throws Exception {
775     String jwksString =
776         "{"
777             + "\"keys\":[{"
778             + "\"crv\":\"P-256\","
779             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
780             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
781             + "\"use\":\"sig\","
782             + "\"alg\":\"ES256\","
783             + "\"key_ops\":[\"verify\"]"
784             + "}]}";
785     assertThrows(
786         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
787   }
788 
789   @Test
ecdsaWithoutCrv_toPublicKeysetHandleFails()790   public void ecdsaWithoutCrv_toPublicKeysetHandleFails() throws Exception {
791     String jwksString =
792         "{"
793             + "\"keys\":[{"
794             + "\"kty\":\"EC\","
795             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
796             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
797             + "\"use\":\"sig\","
798             + "\"alg\":\"ES256\","
799             + "\"key_ops\":[\"verify\"]"
800             + "}]}";
801     assertThrows(
802         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
803   }
804 
805   @Test
ecdsa_pointNotOnCurve_getPrimitiveFails()806   public void ecdsa_pointNotOnCurve_getPrimitiveFails() throws Exception {
807     String jwksString =
808         "{"
809             + "\"keys\":[{"
810             + "\"kty\":\"EC\","
811             + "\"crv\":\"P-256\","
812             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
813             + "\"y\":\"AAAwOQ\","
814             + "\"use\":\"sig\","
815             + "\"alg\":\"ES256\","
816             + "\"key_ops\":[\"verify\"]"
817             + "}]}";
818     assertThrows(
819         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
820   }
821 
822   @Test
ecdsaWithInvalidKty_toPublicKeysetHandleFails()823   public void ecdsaWithInvalidKty_toPublicKeysetHandleFails() throws Exception {
824     String jwksString =
825         "{"
826             + "\"keys\":[{"
827             + "\"kty\":\"RSA\","
828             + "\"crv\":\"P-256\","
829             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
830             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
831             + "\"use\":\"sig\","
832             + "\"alg\":\"ES256\","
833             + "\"key_ops\":[\"verify\"]"
834             + "}]}";
835     assertThrows(
836         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
837   }
838 
839   @Test
ecdsaWithInvalidCrv_toPublicKeysetHandleFails()840   public void ecdsaWithInvalidCrv_toPublicKeysetHandleFails() throws Exception {
841     String jwksString =
842         "{"
843             + "\"keys\":[{"
844             + "\"kty\":\"EC\","
845             + "\"crv\":\"P-384\","
846             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
847             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
848             + "\"use\":\"sig\","
849             + "\"alg\":\"ES256\","
850             + "\"key_ops\":[\"verify\"]"
851             + "}]}";
852     assertThrows(
853         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
854   }
855 
856   @Test
ecdsaWithInvalidUse_toPublicKeysetHandleFails()857   public void ecdsaWithInvalidUse_toPublicKeysetHandleFails() throws Exception {
858     String jwksString =
859         "{"
860             + "\"keys\":[{"
861             + "\"kty\":\"EC\","
862             + "\"crv\":\"P-256\","
863             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
864             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
865             + "\"use\":\"invalid\","
866             + "\"alg\":\"ES256\","
867             + "\"key_ops\":[\"verify\"]"
868             + "}]}";
869     assertThrows(
870         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
871   }
872 
873   @Test
ecdsaWithInvalidKeyOps_toPublicKeysetHandleFails()874   public void ecdsaWithInvalidKeyOps_toPublicKeysetHandleFails() throws Exception {
875     String jwksString =
876         "{"
877             + "\"keys\":[{"
878             + "\"kty\":\"EC\","
879             + "\"crv\":\"P-256\","
880             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
881             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
882             + "\"use\":\"sig\","
883             + "\"alg\":\"ES256\","
884             + "\"key_ops\":[\"invalid\"]"
885             + "}]}";
886     assertThrows(
887         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
888   }
889 
890   @Test
ecdsaWithStringKeyOps_toPublicKeysetHandleFails()891   public void ecdsaWithStringKeyOps_toPublicKeysetHandleFails() throws Exception {
892     String jwksString =
893         "{"
894             + "\"keys\":[{"
895             + "\"kty\":\"EC\","
896             + "\"crv\":\"P-256\","
897             + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\","
898             + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\","
899             + "\"use\":\"sig\","
900             + "\"alg\":\"ES256\","
901             + "\"key_ops\":\"verify\""
902             + "}]}";
903     assertThrows(
904         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
905   }
906 
907   @Test
rsaWithoutUseAndKeyOps_toPublicKeysetHandleSuccess()908   public void rsaWithoutUseAndKeyOps_toPublicKeysetHandleSuccess() throws Exception {
909     String jwksString =
910         "{\"keys\":[{\"kty\":\"RSA\","
911             + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks"
912             + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T"
913             + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6"
914             + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY"
915             + "2oFr3AwKBYDHvsc\","
916             + "\"e\":\"AQAB\",\"alg\":\"RS256\"}]}";
917     // ignore returned value, we only test that it worked.
918     Object unused = JwkSetConverter.toPublicKeysetHandle(jwksString);
919 
920     String psJwksString = jwksString.replace("RS256", "PS256");
921     // ignore returned value, we only test that it worked.
922     unused = JwkSetConverter.toPublicKeysetHandle(psJwksString);
923   }
924 
925   @Test
rsaWithUnknownField_toPublicKeysetHandleSuccess()926   public void rsaWithUnknownField_toPublicKeysetHandleSuccess() throws Exception {
927     String jwksString =
928         "{\"keys\":[{\"kty\":\"RSA\","
929             + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks"
930             + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T"
931             + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6"
932             + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY"
933             + "2oFr3AwKBYDHvsc\","
934             + "\"unknown\":1234,"
935             + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}";
936     // ignore returned value, we only test that it worked.
937     Object unused = JwkSetConverter.toPublicKeysetHandle(jwksString);
938 
939     String psJwksString = jwksString.replace("RS256", "PS256");
940     // ignore returned value, we only test that it worked.
941     unused = JwkSetConverter.toPublicKeysetHandle(psJwksString);
942   }
943 
944   @Test
rsaPrivateKey_fails()945   public void rsaPrivateKey_fails() throws Exception {
946     // Example from https://datatracker.ietf.org/doc/html/rfc7517#appendix-A.2
947     String jwksString =
948         "{\"keys\":["
949             + "{\"kty\":\"RSA\","
950             + "\"n\":\"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4"
951             + "cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMst"
952             + "n64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2Q"
953             + "vzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS"
954             + "D08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw"
955             + "0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\","
956             + "\"e\":\"AQAB\","
957             + "\"d\":\"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9"
958             + "M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqij"
959             + "wp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d"
960             + "_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBz"
961             + "nbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFz"
962             + "me1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q\","
963             + "\"p\":\"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPV"
964             + "nwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqV"
965             + "WlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs\","
966             + "\"q\":\"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyum"
967             + "qjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgx"
968             + "kIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk\","
969             + "\"dp\":\"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oim"
970             + "YwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_Nmtu"
971             + "YZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0\","
972             + "\"dq\":\"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUU"
973             + "vMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9"
974             + "GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk\","
975             + "\"qi\":\"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzg"
976             + "UIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rx"
977             + "yR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU\","
978             + "\"alg\":\"RS256\","
979             + "\"kid\":\"2011-04-29\"}]}";
980     assertThrows(
981         UnsupportedOperationException.class,
982         () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
983 
984     String psJwksString = jwksString.replace("RS256", "PS256");
985     assertThrows(
986         UnsupportedOperationException.class,
987         () -> JwkSetConverter.toPublicKeysetHandle(psJwksString));
988   }
989 
990   @Test
rsaWithoutAlg_toPublicKeysetHandleFails()991   public void rsaWithoutAlg_toPublicKeysetHandleFails() throws Exception {
992     String jwksString =
993         "{\"keys\":[{\"kty\":\"RSA\","
994             + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks"
995             + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T"
996             + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6"
997             + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY"
998             + "2oFr3AwKBYDHvsc\","
999             + "\"e\":\"AQAB\",\"use\":\"sig\",\"key_ops\":[\"verify\"]}]}";
1000     assertThrows(
1001         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
1002   }
1003 
1004   @Test
rsaWithoutKty_toPublicKeysetHandleFails()1005   public void rsaWithoutKty_toPublicKeysetHandleFails() throws Exception {
1006     String jwksString =
1007         "{\"keys\":[{"
1008             + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks"
1009             + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T"
1010             + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6"
1011             + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY"
1012             + "2oFr3AwKBYDHvsc\","
1013             + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}";
1014     assertThrows(
1015         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
1016 
1017     String psJwksString = jwksString.replace("RS256", "PS256");
1018     assertThrows(
1019         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString));
1020   }
1021 
1022   @Test
rsaWithSmallN_getPrimitiveFails()1023   public void rsaWithSmallN_getPrimitiveFails() throws Exception {
1024     String jwksString =
1025         "{\"keys\":[{\"kty\":\"RSA\","
1026             + "\"n\":\"AAAwOQ\","
1027             + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}";
1028     assertThrows(
1029         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
1030 
1031     String psJwksString = jwksString.replace("RS256", "PS256");
1032     assertThrows(
1033         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString));
1034   }
1035 
1036   @Test
rsaWithInvalidKty_toPublicKeysetHandleFails()1037   public void rsaWithInvalidKty_toPublicKeysetHandleFails() throws Exception {
1038     String jwksString =
1039         "{\"keys\":[{\"kty\":\"EC\","
1040             + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks"
1041             + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T"
1042             + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6"
1043             + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY"
1044             + "2oFr3AwKBYDHvsc\","
1045             + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}";
1046     assertThrows(
1047         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
1048 
1049     String psJwksString = jwksString.replace("RS256", "PS256");
1050     assertThrows(
1051         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString));
1052   }
1053 
1054   @Test
rsaWithInvalidUse_toPublicKeysetHandleFails()1055   public void rsaWithInvalidUse_toPublicKeysetHandleFails() throws Exception {
1056     String jwksString =
1057         "{\"keys\":[{\"kty\":\"RSA\","
1058             + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks"
1059             + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T"
1060             + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6"
1061             + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY"
1062             + "2oFr3AwKBYDHvsc\","
1063             + "\"e\":\"AQAB\",\"use\":\"invalid\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}";
1064     assertThrows(
1065         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
1066 
1067     String psJwksString = jwksString.replace("RS256", "PS256");
1068     assertThrows(
1069         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString));
1070   }
1071 
1072   @Test
rsaWithInvalidKeyOps_toPublicKeysetHandleFails()1073   public void rsaWithInvalidKeyOps_toPublicKeysetHandleFails() throws Exception {
1074     String jwksString =
1075         "{\"keys\":[{\"kty\":\"RSA\","
1076             + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks"
1077             + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T"
1078             + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6"
1079             + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY"
1080             + "2oFr3AwKBYDHvsc\","
1081             + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"invalid\"]}]}";
1082     assertThrows(
1083         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
1084 
1085     String psJwksString = jwksString.replace("RS256", "PS256");
1086     assertThrows(
1087         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString));
1088   }
1089 
1090   @Test
rsaWithStringKeyOps_toPublicKeysetHandleFails()1091   public void rsaWithStringKeyOps_toPublicKeysetHandleFails() throws Exception {
1092     String jwksString =
1093         "{\"keys\":[{\"kty\":\"RSA\","
1094             + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks"
1095             + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T"
1096             + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6"
1097             + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY"
1098             + "2oFr3AwKBYDHvsc\","
1099             + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":\"verify\"}]}";
1100     assertThrows(
1101         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString));
1102 
1103     String psJwksString = jwksString.replace("RS256", "PS256");
1104     assertThrows(
1105         GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString));
1106   }
1107 
1108   @Test
jwksetWithDuplicateMapKey_fails()1109   public void jwksetWithDuplicateMapKey_fails() throws Exception {
1110     String jwkSetWithDuplicateMapKey =
1111         "{\"keys\":[{"
1112             + "\"kty\":\"EC\","
1113             + "\"kty\":\"EC\","
1114             + "\"crv\":\"P-256\","
1115             + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\","
1116             + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\","
1117             + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"]}]}";
1118     assertThrows(
1119         GeneralSecurityException.class,
1120         () -> JwkSetConverter.toPublicKeysetHandle(jwkSetWithDuplicateMapKey));
1121   }
1122 
1123   @Test
jwksetAsJsonArray_fails()1124   public void jwksetAsJsonArray_fails() throws Exception {
1125     String jwksetAsJsonArray =
1126         "[{"
1127             + "\"kty\":\"EC\","
1128             + "\"crv\":\"P-256\","
1129             + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\","
1130             + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\","
1131             + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"]}]";
1132     assertThrows(
1133         GeneralSecurityException.class,
1134         () -> JwkSetConverter.toPublicKeysetHandle(jwksetAsJsonArray));
1135   }
1136 
1137   @Test
1138   @SuppressWarnings("InlineMeInliner")
deprecatedFromKeysetHandle_sameAs_fromPublicKeysetHandle()1139   public void deprecatedFromKeysetHandle_sameAs_fromPublicKeysetHandle()
1140       throws Exception {
1141     KeysetHandle handle =
1142         TinkJsonProtoKeysetFormat.parseKeyset(ES256_KEYSET, InsecureSecretKeyAccess.get());
1143     assertEqualJwkSets(
1144         JwkSetConverter.fromKeysetHandle(handle, KeyAccess.publicAccess()),
1145         JwkSetConverter.fromPublicKeysetHandle(handle));
1146   }
1147 
1148   @Test
1149   @SuppressWarnings("InlineMeInliner")
deprecatedToKeysetHandle_sameAs_toPublicKeysetHandle()1150   public void deprecatedToKeysetHandle_sameAs_toPublicKeysetHandle()
1151       throws Exception {
1152     KeysetHandle handle = JwkSetConverter.toPublicKeysetHandle(ES256_JWK_SET);
1153     KeysetHandle deprecatedHandle =
1154         JwkSetConverter.toKeysetHandle(ES256_JWK_SET, KeyAccess.publicAccess());
1155     assertEqualJwkSets(
1156       JwkSetConverter.fromPublicKeysetHandle(handle),
1157       JwkSetConverter.fromPublicKeysetHandle(deprecatedHandle));
1158   }
1159 }
1160