// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package com.google.crypto.tink.jwt; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import com.google.crypto.tink.InsecureSecretKeyAccess; import com.google.crypto.tink.KeyTemplates; import com.google.crypto.tink.KeysetHandle; import com.google.crypto.tink.RegistryConfiguration; import com.google.crypto.tink.TinkJsonProtoKeysetFormat; import com.google.crypto.tink.TinkProtoKeysetFormat; import com.google.crypto.tink.proto.KeyData; import com.google.crypto.tink.proto.KeyData.KeyMaterialType; import com.google.crypto.tink.proto.KeyStatusType; import com.google.crypto.tink.proto.Keyset; import com.google.crypto.tink.subtle.Base64; import com.google.crypto.tink.testing.TestUtil; import com.google.crypto.tink.tinkkey.KeyAccess; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.protobuf.ByteString; import java.security.GeneralSecurityException; import org.junit.Before; import org.junit.Test; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.FromDataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; /** Unit tests for JwkSetConverter */ @RunWith(Theories.class) public final class JwkSetConverterTest { @Before public void setup() throws Exception { JwtSignatureConfig.register(); } private static final String ES256_KEYSET = "{\"primaryKeyId\":282600252,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\"," + "\"value\":\"EAEaIBDPI66hjLHvjxmUJ2nyHIBDmdOtQ4gPsvWgYYgZ0gygIiBTEK0rTACpAb97m+mvtJKAk0" + "q3mHjPcUZm0C4EueDW4Q==\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":282600252,\"outputPrefixType\":\"RAW\"}]}"; private static final String ES256_JWK_SET = "{\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\"," + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\"," + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"]}]}"; private static final String ES256_KEYSET_TINK = "{\"primaryKeyId\":282600252,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\"," + "\"value\":\"EAEaIBDPI66hjLHvjxmUJ2nyHIBDmdOtQ4gPsvWgYYgZ0gygIiBTEK0rTACpAb97m+mvtJKAk0" + "q3mHjPcUZm0C4EueDW4Q==\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":282600252,\"outputPrefixType\":\"TINK\"}]}"; private static final String ES256_JWK_SET_KID = "{\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\"," + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\"," + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"]," + "\"kid\":\"ENgjPA\"}]}"; private static final String ES256_JWK_SET_KID_TINK = "{\"primaryKeyId\":1623060913,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\"," + "\"value\":\"EAEaIQAQzyOuoYyx748ZlCdp8hyAQ5nTrUOID7L1oGGIGdIMoCIhAFMQrStMAKkBv3ub6a+0ko" + "CTSreYeM9xRmbQLgS54NbhKggKBkVOZ2pQQQ==\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"}," + "\"status\":\"ENABLED\",\"keyId\":1623060913,\"outputPrefixType\":\"RAW\"}]}"; private static final String ES384_KEYSET = "{\"primaryKeyId\":456087424,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\"," + "\"value\":\"EAIaMQDSjvWihoKGmr4nlDuI/KkvuPvEZr+B4bU0MuXQQXgyNMGApFm2iTeotv7LCSsG3mQiME" + "HIMGx4wa+Y8yeJQWMiSpukpPM7jP9GqaykZQQ2GY/NLg/n9+BJtntgvFhG5gWLTg==\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":456087424,\"outputPrefixType\":\"RAW\"}]}"; private static final String ES384_JWK_SET = "{\"keys\":[{\"kty\":\"EC\",\"crv\":\"P-384\"," + "\"x\":\"0o71ooaChpq-J5Q7iPypL7j7xGa_geG1NDLl0EF4MjTBgKRZtok3qLb-ywkrBt5k\"," + "\"y\":\"QcgwbHjBr5jzJ4lBYyJKm6Sk8zuM_0aprKRlBDYZj80uD-f34Em2e2C8WEbmBYtO\"," + "\"use\":\"sig\",\"alg\":\"ES384\",\"key_ops\":[\"verify\"]}]}"; private static final String ES512_KEYSET = "{\"primaryKeyId\":1570200439,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\"," + "\"value\":\"EAMaQgEV3nweRej6Z1/aPTqCkc1tQla5eVI68+qfwR1kB/wXCuYCB5otarhomUt64Fah/8Tjf0" + "WJHMZyFr86RUitiRQm1SJCATht/NOX8RcbaEr1MaH+0BFTaepvpTzSfQ04C2P8VCoURB3GeVKk4VQh8O/KLSYf" + "X+58bqEnaZ0G7W9qjHa2ols2\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":1570200439,\"outputPrefixType\":\"RAW\"}]}"; private static final String ES512_JWK_SET = "{\"keys\":[{\"kty\":\"EC\",\"crv\":\"P-521\"," + "\"x\":\"ARXefB5F6PpnX9o9OoKRzW1CVrl5Ujrz6p_BHWQH_BcK5gIHmi1quGiZS3rgVqH_xON_RYkcxnIWvzpFSK2JFCbV\"," + "\"y\":\"ATht_NOX8RcbaEr1MaH-0BFTaepvpTzSfQ04C2P8VCoURB3GeVKk4VQh8O_KLSYfX-58bqEnaZ0G7W9qjHa2ols2\"," + "\"use\":\"sig\",\"alg\":\"ES512\",\"key_ops\":[\"verify\"]}]}"; private static final String RS256_KEYSET = "{\"primaryKeyId\":482168993,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\"," + "\"value\":\"EAEagQIAkspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwf" + "GMClfe/alIs2GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI+5hZ6ifUsv8W8mSHKlsVMmvOf" + "C2P5+l72qTwN6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B/n7nfiWw9YN5++pfwyoitzoMoVKOOpj7fF" + "q88f8ArpC7kR1SBTe20Bt1AmpZDT2Dmfmlb/Q1UFjj/F3C77NCNQ344ZcAEI42HY+uighy5GdKQRHMoTT1OzyD" + "G90ABjggQqDGW+zXzyIDAQAB\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":482168993,\"outputPrefixType\":\"RAW\"}]}"; // private static final String RS256_JWK_SET = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"kspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwfGMClfe_alIs2" + "GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI-5hZ6ifUsv8W8mSHKlsVMmvOfC2P5-l72qTwN" + "6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B_n7nfiWw9YN5--pfwyoitzoMoVKOOpj7fFq88f8ArpC7kR" + "1SBTe20Bt1AmpZDT2Dmfmlb_Q1UFjj_F3C77NCNQ344ZcAEI42HY-uighy5GdKQRHMoTT1OzyDG90ABjggQqDG" + "W-zXzw\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}"; private static final String RS256_KEYSET_TINK = "{\"primaryKeyId\":482168993,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\"," + "\"value\":\"EAEagQIAkspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwf" + "GMClfe/alIs2GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI+5hZ6ifUsv8W8mSHKlsVMmvOf" + "C2P5+l72qTwN6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B/n7nfiWw9YN5++pfwyoitzoMoVKOOpj7fF" + "q88f8ArpC7kR1SBTe20Bt1AmpZDT2Dmfmlb/Q1UFjj/F3C77NCNQ344ZcAEI42HY+uighy5GdKQRHMoTT1OzyD" + "G90ABjggQqDGW+zXzyIDAQAB\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":482168993,\"outputPrefixType\":\"TINK\"}]}"; private static final String RS256_JWK_SET_KID = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"kspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwfGMClfe_alIs2" + "GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI-5hZ6ifUsv8W8mSHKlsVMmvOfC2P5-l72qTwN" + "6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B_n7nfiWw9YN5--pfwyoitzoMoVKOOpj7fFq88f8ArpC7kR" + "1SBTe20Bt1AmpZDT2Dmfmlb_Q1UFjj_F3C77NCNQ344ZcAEI42HY-uighy5GdKQRHMoTT1OzyDG90ABjggQqDG" + "W-zXzw\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]," + "\"kid\":\"HL1QoQ\"}]}"; private static final String RS256_JWK_SET_KID_TINK = "{\"primaryKeyId\":1204986267,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\"," + "\"value\":\"EAEagQIAkspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwf" + "GMClfe/alIs2GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI+5hZ6ifUsv8W8mSHKlsVMmvOf" + "C2P5+l72qTwN6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B/n7nfiWw9YN5++pfwyoitzoMoVKOOpj7fF" + "q88f8ArpC7kR1SBTe20Bt1AmpZDT2Dmfmlb/Q1UFjj/F3C77NCNQ344ZcAEI42HY+uighy5GdKQRHMoTT1OzyD" + "G90ABjggQqDGW+zXzyIDAQABKggKBkhMMVFvUQ==\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"}," + "\"status\":\"ENABLED\",\"keyId\":1204986267,\"outputPrefixType\":\"RAW\"}]}"; private static final String RS384_KEYSET = "{\"primaryKeyId\":333504275,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\"," + "\"value\":\"EAIagQMAnlBY5WD7gVQjNKvrS2whLKzt0Eql72B6haZ17eKifNn4S49eGdBy9RLj/mvHXAbacr" + "ngt9fzi0iv/WQ57jUmtO1b/wLt5LYk9APsBYjywDCIe+u9UouikP7c3SBqjjQijZ50jgYbMY6cL7s2Gx5lI1vl" + "GX3ZExLVYbNoI9VBFAWjSDefd6GugESxXQFnnO3p2GHOKryZLeDH/KzVacTq2/pVXKVH/9/EQzcLB0oYUljZ4v" + "YQ4HCAcwnUZbirsRwA0350Dz0Mlj+3+9sSAF8FPA+F/wlIBkPqjJ26b80V5FU4mBTzvYoXGTjkD7+bxH9p28hu" + "JSU96P4WdG5PYVwI1VEYwGipkUIpMWjJ7dXAtmltHzM9vkUt2bsBe9vyJjmRXyoC6mHSJbSyOm9Dd8BENobcUL" + "9h+aBoxruY+mU49kAHzzeAntn8C+vIrxN+X6N2EU9N8t9BF+mwYiBEsY54wx99RbRrY9yICfPBmQJGwXSxNCXB" + "RrbJyxkIVuqvACP5IgMBAAE=\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":333504275,\"outputPrefixType\":\"RAW\"}]}"; private static final String RS384_JWK_SET = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"nlBY5WD7gVQjNKvrS2whLKzt0Eql72B6haZ17eKifNn4S49eGdBy9RLj_mvHXAbacrngt9fzi0iv_W" + "Q57jUmtO1b_wLt5LYk9APsBYjywDCIe-u9UouikP7c3SBqjjQijZ50jgYbMY6cL7s2Gx5lI1vlGX3ZExLVYbNo" + "I9VBFAWjSDefd6GugESxXQFnnO3p2GHOKryZLeDH_KzVacTq2_pVXKVH_9_EQzcLB0oYUljZ4vYQ4HCAcwnUZb" + "irsRwA0350Dz0Mlj-3-9sSAF8FPA-F_wlIBkPqjJ26b80V5FU4mBTzvYoXGTjkD7-bxH9p28huJSU96P4WdG5P" + "YVwI1VEYwGipkUIpMWjJ7dXAtmltHzM9vkUt2bsBe9vyJjmRXyoC6mHSJbSyOm9Dd8BENobcUL9h-aBoxruY-m" + "U49kAHzzeAntn8C-vIrxN-X6N2EU9N8t9BF-mwYiBEsY54wx99RbRrY9yICfPBmQJGwXSxNCXBRrbJyxkIVuqv" + "ACP5\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS384\",\"key_ops\":[\"verify\"]}]}"; private static final String RS512_KEYSET = "{\"primaryKeyId\":705596479,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\"," + "\"value\":\"EAMagQQAkKxZ9IRzF56gh47RXLJzQ6lffcnBmQSwvxUDJ0wHpKZzfAawOn1uidbgEoQ3XWOgtN" + "vi7QeKLE4GjQa5bY0xdRnu8nKjFcsvH+eu1sV8oVoZ984J5mT1mhwU6nt26p4xKyeapMhzYYNvKudQjQJ8SbpV" + "OFpEiJ7j0ECMUd4Q8mCUqWsrXYE8+1CcHjprsIxdot+haCARc72RBj9cLuBIhJNzlFXNmsYh8yoSiEYr/auRvg" + "/kIlNlnlOK/rJM/jMXbB6FuWdePrtqZ+ce2TVyARqjZJ0G0vZcPuvOhgS4LM7/Aeal84ZhIcHladSo/g8pK1eU" + "hnRqRXJpsltwux+1XVJeg2a0FQ0BN3Ft25uu5jhfvGWXeTkQOR7LbpbxKTI+vumSy9dmY4UrgAG37N8Xj5/Neq" + "BT51L3qE6tk2ZLoO7yjRjhADK5lnbb4iYWWvWd3kqyv0JVlxfDzjAaYtiduEUIdCe45MGk8DpCn9Lnjlunhm4Q" + "yQufK8k8UPiBbWNEODI8pjTSEjs0wyMqhegBKAvtVEhr029bg3Lv7YjN9FDvx4usuWGc16bXkTqNgCK4KzPG7P" + "wV120r6IVGflfpSkd5rrkzDY01fsP0mW57QCHA67bxqLUECr2dAfNzz6ddS9pqXQyXZWCyWKcvTFsGrr1oECwD" + "OmW+nUIHGklr9Q0iAwEAAQ==\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":705596479,\"outputPrefixType\":\"RAW\"}]}"; private static final String RS512_JWK_SET = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"kKxZ9IRzF56gh47RXLJzQ6lffcnBmQSwvxUDJ0wHpKZzfAawOn1uidbgEoQ3XWOgtNvi7QeKLE4GjQ" + "a5bY0xdRnu8nKjFcsvH-eu1sV8oVoZ984J5mT1mhwU6nt26p4xKyeapMhzYYNvKudQjQJ8SbpVOFpEiJ7j0ECM" + "Ud4Q8mCUqWsrXYE8-1CcHjprsIxdot-haCARc72RBj9cLuBIhJNzlFXNmsYh8yoSiEYr_auRvg_kIlNlnlOK_r" + "JM_jMXbB6FuWdePrtqZ-ce2TVyARqjZJ0G0vZcPuvOhgS4LM7_Aeal84ZhIcHladSo_g8pK1eUhnRqRXJpsltw" + "ux-1XVJeg2a0FQ0BN3Ft25uu5jhfvGWXeTkQOR7LbpbxKTI-vumSy9dmY4UrgAG37N8Xj5_NeqBT51L3qE6tk2" + "ZLoO7yjRjhADK5lnbb4iYWWvWd3kqyv0JVlxfDzjAaYtiduEUIdCe45MGk8DpCn9Lnjlunhm4QyQufK8k8UPiB" + "bWNEODI8pjTSEjs0wyMqhegBKAvtVEhr029bg3Lv7YjN9FDvx4usuWGc16bXkTqNgCK4KzPG7PwV120r6IVGfl" + "fpSkd5rrkzDY01fsP0mW57QCHA67bxqLUECr2dAfNzz6ddS9pqXQyXZWCyWKcvTFsGrr1oECwDOmW-nUIHGklr" + "9Q0\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS512\",\"key_ops\":[\"verify\"]}]}"; private static final String PS256_KEYSET = "{\"primaryKeyId\":1508587714,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\"," + "\"value\":\"EAEagQMAj7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d+Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1" + "TMmksY2Ugf/7+Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz+9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed+TLIlgvw" + "uSTF4B5d6QkZWBymq7My6vV+epzWnoLpVDzCHh+c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDg" + "wQ63rVCo2eWDS/BYK4rG22luSTDVfQVHU1NXlwXEnb/eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy" + "3XiSeCGtghBXLMf/ge113Q9WDJ+RN1Xa4vgHJCO0+VO+cAugVkiu9UgsPP8o/r7tA2aP/Ps8EHYa1IaZg75vnr" + "MZPvsTH7WG2SjSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX/PN6DLKoK2PaT0I+iLK9mRi1Z4OjFbl9KA" + "ZXXElhAQTzrEI2adIgMBAAE=\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":1508587714,\"outputPrefixType\":\"RAW\"}]}"; private static final String PS256_JWK_SET = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"j7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d-Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1TMmksY2Ugf_7" + "-Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz-9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed-TLIlgvwuSTF4B5d6QkZ" + "WBymq7My6vV-epzWnoLpVDzCHh-c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDgwQ63rVCo2eWD" + "S_BYK4rG22luSTDVfQVHU1NXlwXEnb_eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy3XiSeCGtghBX" + "LMf_ge113Q9WDJ-RN1Xa4vgHJCO0-VO-cAugVkiu9UgsPP8o_r7tA2aP_Ps8EHYa1IaZg75vnrMZPvsTH7WG2S" + "jSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX_PN6DLKoK2PaT0I-iLK9mRi1Z4OjFbl9KAZXXElhAQTzrE" + "I2ad\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"PS256\",\"key_ops\":[\"verify\"]}]}"; private static final String PS256_KEYSET_TINK = "{\"primaryKeyId\":1508587714,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\"," + "\"value\":\"EAEagQMAj7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d+Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1" + "TMmksY2Ugf/7+Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz+9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed+TLIlgvw" + "uSTF4B5d6QkZWBymq7My6vV+epzWnoLpVDzCHh+c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDg" + "wQ63rVCo2eWDS/BYK4rG22luSTDVfQVHU1NXlwXEnb/eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy" + "3XiSeCGtghBXLMf/ge113Q9WDJ+RN1Xa4vgHJCO0+VO+cAugVkiu9UgsPP8o/r7tA2aP/Ps8EHYa1IaZg75vnr" + "MZPvsTH7WG2SjSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX/PN6DLKoK2PaT0I+iLK9mRi1Z4OjFbl9KA" + "ZXXElhAQTzrEI2adIgMBAAE=\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":1508587714,\"outputPrefixType\":\"TINK\"}]}"; private static final String PS256_JWK_SET_KID = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"j7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d-Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1TMmksY2Ugf_7" + "-Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz-9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed-TLIlgvwuSTF4B5d6QkZ" + "WBymq7My6vV-epzWnoLpVDzCHh-c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDgwQ63rVCo2eWD" + "S_BYK4rG22luSTDVfQVHU1NXlwXEnb_eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy3XiSeCGtghBX" + "LMf_ge113Q9WDJ-RN1Xa4vgHJCO0-VO-cAugVkiu9UgsPP8o_r7tA2aP_Ps8EHYa1IaZg75vnrMZPvsTH7WG2S" + "jSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX_PN6DLKoK2PaT0I-iLK9mRi1Z4OjFbl9KAZXXElhAQTzrE" + "I2ad\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"PS256\",\"key_ops\":[\"verify\"]," + "\"kid\":\"Wes4wg\"}]}"; private static final String PS256_JWK_SET_KID_TINK = "{\"primaryKeyId\":1004877962,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\"," + "\"value\":\"EAEagQMAj7Eud2n5G11qsdtjpgGWjW4cAKalSE1atm7d+Cp8biRX9wbmLJRMUvoO2j7Sp9Szx1" + "TMmksY2Ugf/7+Nv9fY7vBbmxOiBQVTvikWn0FgPwhFTXTz+9fhGjM6E6sdSOUzjM6nsPulKqOQ8Aed+TLIlgvw" + "uSTF4B5d6QkZWBymq7My6vV+epzWnoLpVDzCHh+c35r81Pyrj6tiTPQzPLN2ixeanclMjx8deNwlak3vwBdMDg" + "wQ63rVCo2eWDS/BYK4rG22luSTDVfQVHU1NXlwXEnb/eONFSF6ZbD6JXFMT3uHT4okTOrX4Kd34stbPIUtZFUy" + "3XiSeCGtghBXLMf/ge113Q9WDJ+RN1Xa4vgHJCO0+VO+cAugVkiu9UgsPP8o/r7tA2aP/Ps8EHYa1IaZg75vnr" + "MZPvsTH7WG2SjSgW9GLLsbNJLFFqLFMwPuZPe8BbgvimPdStXasX/PN6DLKoK2PaT0I+iLK9mRi1Z4OjFbl9KA" + "ZXXElhAQTzrEI2adIgMBAAEqCAoGV2VzNHdn\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"}," + "\"status\":\"ENABLED\",\"keyId\":1004877962,\"outputPrefixType\":\"RAW\"}]}"; private static final String PS384_KEYSET = "{\"primaryKeyId\":1042230435,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\"," + "\"value\":\"EAIagQMAv6a0OergWYmY1k6l6vx6Of5+RxCeeQ9jMTXQyvO0GCgMDExxtqVS8S25ehZ5LNDIiG" + "jhE3v2++D7QEjnzOC5UqI1ZwPxUBSrOaf5oDbJ9vBc2c7wDyJhRV8UobQSpzunD4kXypVhytjwRdiP61vG0C/e" + "L0x+LijtM/XVee1Y+5mWrypVrB6EHKtdkMx2WIYNpsFOForFrr6JzLbWfDRWoqbCXKYivnw+CSE38ddW1XsrAT" + "76E2Vf+womuwyBbkjLaiWvNxNFBTap2IaBLKAni6x7pqYCeu1n9eMUi41oz9QM8xfOvpH+wubc2PjwyTsb1FDT" + "LnhV36tQLTVGdQdCDMF2Z8Agrnio3n1SFjSbYgFyVtpCwFKM2Z0zfO7k9jVbYYkzglzkJfp/lQrsuWqe4CVJjF" + "E1H4BxcU7L0j8755kGJI08h1b7LPgqJcPgtHjcqbxHFU2yOf7mNGlW7YTnoQBO0StzQUk7kEw3X0+niEwX/L8j" + "qW4YMbxrGdAfkTnPIgMBAAE=\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":1042230435,\"outputPrefixType\":\"RAW\"}]}"; private static final String PS384_JWK_SET = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"v6a0OergWYmY1k6l6vx6Of5-RxCeeQ9jMTXQyvO0GCgMDExxtqVS8S25ehZ5LNDIiGjhE3v2--D7QE" + "jnzOC5UqI1ZwPxUBSrOaf5oDbJ9vBc2c7wDyJhRV8UobQSpzunD4kXypVhytjwRdiP61vG0C_eL0x-LijtM_XV" + "ee1Y-5mWrypVrB6EHKtdkMx2WIYNpsFOForFrr6JzLbWfDRWoqbCXKYivnw-CSE38ddW1XsrAT76E2Vf-womuw" + "yBbkjLaiWvNxNFBTap2IaBLKAni6x7pqYCeu1n9eMUi41oz9QM8xfOvpH-wubc2PjwyTsb1FDTLnhV36tQLTVG" + "dQdCDMF2Z8Agrnio3n1SFjSbYgFyVtpCwFKM2Z0zfO7k9jVbYYkzglzkJfp_lQrsuWqe4CVJjFE1H4BxcU7L0j" + "8755kGJI08h1b7LPgqJcPgtHjcqbxHFU2yOf7mNGlW7YTnoQBO0StzQUk7kEw3X0-niEwX_L8jqW4YMbxrGdAf" + "kTnP\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"PS384\",\"key_ops\":[\"verify\"]}]}"; private static final String PS512_KEYSET = "{\"primaryKeyId\":257081135,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey\"," + "\"value\":\"EAMagQQAnOUQvBwNRgeI3zlzIhVo4NzFVCsQn9hd2EIclz6cWBRMFr4EX5lXLK0StSIB7EQP4c" + "iHa+vr59sOgMFMC2kiXRUXNtl99QhGwH0YjbWeDC50PKEAjH1hhhPgSw2dFcUVs4jbScDrwNn1sQ8rkgSNczvQ" + "NpV1MtBhS/CC1PxVF88JaejG2zr+unoFlw7xnqxBWMzNrMHZHwqga2vL3inSbvA/RGQjnE2DzQSwZkXthGSwYB" + "jOYbGawMN4onkAx/myHMyTg/TLAqG9GUyB0DVelvVoGZG/QJBY2Fp2FlpOQRKeBr6pC7Lk8zZL4GJk264KoOpG" + "8v1t7PveN+STIdTE2D548K+GDOvsvrO4ZhofS/iqN9xLucuU1HkqKUqyLvMxsWum8Zhp7zinFdBnDOgeheOHUg" + "N/iwjupk6u1Svt+RWNJsfb2l0jrvzf0cRMbPeLZRmpDwBxBvXWo61u6uaBEVb+ooZ6K5+hx3Rld7wXktjYIZzH" + "qUr39P5yTw28b8Y2dPFWR4vwr2/0zBxcDmTRRtQ7vPOtZPD0/LVIXkgbBiLILpycnucWt9Lq9Hc62KFiTQOAuu" + "Oxz7ObBegXjnFupiZZ9PyzO5WgT9lRpH7U7tzGLAjV+AUpjH6HA1o6bRLKOHFBPS+I9IqAYb/RpF6M/6hCmC2R" + "z64yYzR3y4vHKGMiAwEAAQ==\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":257081135,\"outputPrefixType\":\"RAW\"}]}"; private static final String PS512_JWK_SET = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"nOUQvBwNRgeI3zlzIhVo4NzFVCsQn9hd2EIclz6cWBRMFr4EX5lXLK0StSIB7EQP4ciHa-vr59sOgM" + "FMC2kiXRUXNtl99QhGwH0YjbWeDC50PKEAjH1hhhPgSw2dFcUVs4jbScDrwNn1sQ8rkgSNczvQNpV1MtBhS_CC" + "1PxVF88JaejG2zr-unoFlw7xnqxBWMzNrMHZHwqga2vL3inSbvA_RGQjnE2DzQSwZkXthGSwYBjOYbGawMN4on" + "kAx_myHMyTg_TLAqG9GUyB0DVelvVoGZG_QJBY2Fp2FlpOQRKeBr6pC7Lk8zZL4GJk264KoOpG8v1t7PveN-ST" + "IdTE2D548K-GDOvsvrO4ZhofS_iqN9xLucuU1HkqKUqyLvMxsWum8Zhp7zinFdBnDOgeheOHUgN_iwjupk6u1S" + "vt-RWNJsfb2l0jrvzf0cRMbPeLZRmpDwBxBvXWo61u6uaBEVb-ooZ6K5-hx3Rld7wXktjYIZzHqUr39P5yTw28" + "b8Y2dPFWR4vwr2_0zBxcDmTRRtQ7vPOtZPD0_LVIXkgbBiLILpycnucWt9Lq9Hc62KFiTQOAuuOxz7ObBegXjn" + "FupiZZ9PyzO5WgT9lRpH7U7tzGLAjV-AUpjH6HA1o6bRLKOHFBPS-I9IqAYb_RpF6M_6hCmC2Rz64yYzR3y4vH" + "KGM\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"PS512\",\"key_ops\":[\"verify\"]}]}"; private static final String P256_PUBLIC_KEYSET_SMALL_COORDINATES = "{\"primaryKeyId\":2124611562,\"key\":[{\"keyData\":{\"typeUrl\":" + " \"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\"" + " ,\"value\":\"EAEaH2lFjtbwLgtzRDh7dV9sYmW4IWl3ZKA+WghvrQPiCNoiIEJ8pQXMy" + " A/JywaGWT+IHmWxuVYWqdxkPsUSHLhSQm51\",\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"}" + " ,\"status\":\"ENABLED\",\"keyId\":2124611562,\"outputPrefixType\":\"TINK\"}]}"; private static final String P384_PUBLIC_KEYSET_SMALL_COORDINATES = "{\"primaryKeyId\":4159170178,\"key\":[{\"keyData\":{" + " \"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\"," + " \"value\":\"EAIaL/bm1+e6X7gat+MJK3e65BGlZzKIf6I1q0Ro8zAKeyryUxgvZl8Ww/NlcVN2XJhEI" + " jA3b73hm8eDfSEEUAAaJbrLZFOFGnSdTWng116r+hOvszYiov+WrsTyIgnL/9aRdN8=\"," + " \"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"},\"status\":\"ENABLED\"," + " \"keyId\":4159170178,\"outputPrefixType\":\"TINK\"}]}"; private static final String P521_PUBLIC_KEYSET_SMALL_COORDINATES = "{\"primaryKeyId\":1286030637,\"key\":[{\"keyData\":{" + " \"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\"," + " \"value\":\"EAMaQUgdEssWf+tdFT3vSoy/OAotV501af+XQ6JSXDjnOPCzZnFh8fYwrJ8Yu8XYF3" + " 3IeHBdAIKyicKuW884JkjYR1qJIkH2OWoa4SOmk0FtpeRBZHPbs7U8SMFXVkaV+HZtjmfl11QGiQU9hqU" + " hoW9ock2K0xg6wdcWBe67YTVFdQbThFmtCg==\",\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"}," + " \"status\":\"ENABLED\",\"keyId\":1286030637,\"outputPrefixType\":\"TINK\"}]}"; private static final String PRIVATEKEY_KEYSET = "{\"primaryKeyId\":152493399,\"key\":[{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPrivateKey\"," + "\"value\":\"EkYQARogaHkaakArEB51RyZ236S5x3BxaNTFycWuXIGZF8adZ2UiIFlZT7MFogZ8ARbS1URIAP" + "cpw8A0g2uwAHRkBqGUiCU2GiBI4jtU/59Zajohgeezi2BXB13O8IJh8V3b0itq5zyy5Q==\"," + "\"keyMaterialType\":\"ASYMMETRIC_PRIVATE\"" + "},\"status\":\"ENABLED\",\"keyId\":152493399,\"outputPrefixType\":\"RAW\"}]}"; private static final String KEYSET_WITH_TWO_KEYS = "{\"primaryKeyId\":282600252,\"key\":[" + "{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey\"," + "\"value\":\"EAEaIBDPI66hjLHvjxmUJ2nyHIBDmdOtQ4gPsvWgYYgZ0gygIiBTEK0rTACpAb97m+mvtJKAk0" + "q3mHjPcUZm0C4EueDW4Q==\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":282600252,\"outputPrefixType\":\"RAW\"}," + "{\"keyData\":{" + "\"typeUrl\":\"type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey\"," + "\"value\":\"EAEagQIAkspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwf" + "GMClfe/alIs2GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI+5hZ6ifUsv8W8mSHKlsVMmvOf" + "C2P5+l72qTwN6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B/n7nfiWw9YN5++pfwyoitzoMoVKOOpj7fF" + "q88f8ArpC7kR1SBTe20Bt1AmpZDT2Dmfmlb/Q1UFjj/F3C77NCNQ344ZcAEI42HY+uighy5GdKQRHMoTT1OzyD" + "G90ABjggQqDGW+zXzyIDAQAB\"," + "\"keyMaterialType\":\"ASYMMETRIC_PUBLIC\"" + "},\"status\":\"ENABLED\",\"keyId\":482168993,\"outputPrefixType\":\"RAW\"}]}"; private static final String JWK_SET_WITH_TWO_KEYS = "{\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\"," + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\"," + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"]}," + "{\"kty\":\"RSA\"," + "\"n\":\"kspk37lGBqXmPPq2CL5KdDeRx7xFiTadpL3jc4nXaqftCtpM6qExfrc2JLaIsnwpwfGMClfe_alIs2" + "GrT9fpM8oDeCccvC39DzZhsSFnAELggi3hnWNKRLfSV0UJzBI-5hZ6ifUsv8W8mSHKlsVMmvOfC2P5-l72qTwN" + "6Le3hy6CxFp5s9pw011B7J3PU65sty6GI9sehB2B_n7nfiWw9YN5--pfwyoitzoMoVKOOpj7fFq88f8ArpC7kR" + "1SBTe20Bt1AmpZDT2Dmfmlb_Q1UFjj_F3C77NCNQ344ZcAEI42HY-uighy5GdKQRHMoTT1OzyDG90ABjggQqDG" + "W-zXzw\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}"; private static void assertEqualJwkSets(String jwkSet1, String jwkSet2) throws Exception { // Consider these strings equal, if their equal after parsing them. // The keys may have any order. JsonObject parsedjwkSet1 = JsonParser.parseString(jwkSet1).getAsJsonObject(); JsonObject parsedjwkSet2 = JsonParser.parseString(jwkSet2).getAsJsonObject(); JsonArray keys1 = parsedjwkSet1.remove("keys").getAsJsonArray(); JsonArray keys2 = parsedjwkSet2.remove("keys").getAsJsonArray(); assertThat(keys1).containsExactlyElementsIn(keys2); assertThat(parsedjwkSet1).isEqualTo(parsedjwkSet2); } @Test public void assertEqualJwkSets_equal() throws Exception { // Whitespace, order of object properties, and order of keys is ignored. assertEqualJwkSets( "{\"keys\":[{\"kty\": \"EC\"}, {\"e\":\"f\",\"kty\": \"RSA\"}]}", "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"f\"}, {\"kty\":\"EC\"}]}"); } @Test public void assertEqualJwkSets_notEequal() throws Exception { // Order of arrays (except "keys" array) is not ignored. assertThrows( AssertionError.class, () -> assertEqualJwkSets( "{\"keys\":[{\"kty\":\"EC\",\"key_ops\":[\"b\",\"c\"]}]}", "{\"keys\":[{\"kty\":\"EC\",\"key_ops\":[\"c\",\"b\"]}]}")); } private static String convertToJwkSet(String jsonKeyset) throws Exception { KeysetHandle handle = TinkJsonProtoKeysetFormat.parseKeyset(jsonKeyset, InsecureSecretKeyAccess.get()); return JwkSetConverter.fromPublicKeysetHandle(handle); } private static byte[] getCoordinate(JsonObject jwkSet, String coordinate) throws Exception { return Base64.urlSafeDecode( jwkSet.get("keys").getAsJsonArray().get(0).getAsJsonObject().get(coordinate).getAsString()); } @Test public void convertEcdsaKeysets_encodesFixedSizeCordinates() throws Exception { JsonObject jwkSet = JsonParser.parseString(convertToJwkSet(P256_PUBLIC_KEYSET_SMALL_COORDINATES)) .getAsJsonObject(); assertThat(getCoordinate(jwkSet, "x")).hasLength(32); assertThat(getCoordinate(jwkSet, "y")).hasLength(32); jwkSet = JsonParser.parseString(convertToJwkSet(P384_PUBLIC_KEYSET_SMALL_COORDINATES)) .getAsJsonObject(); assertThat(getCoordinate(jwkSet, "x")).hasLength(48); assertThat(getCoordinate(jwkSet, "y")).hasLength(48); jwkSet = JsonParser.parseString(convertToJwkSet(P521_PUBLIC_KEYSET_SMALL_COORDINATES)) .getAsJsonObject(); assertThat(getCoordinate(jwkSet, "x")).hasLength(66); assertThat(getCoordinate(jwkSet, "y")).hasLength(66); } @Test public void convertEcdsaKeysets_success() throws Exception { assertEqualJwkSets(convertToJwkSet(ES256_KEYSET), ES256_JWK_SET); assertEqualJwkSets(convertToJwkSet(ES384_KEYSET), ES384_JWK_SET); assertEqualJwkSets(convertToJwkSet(ES512_KEYSET), ES512_JWK_SET); assertEqualJwkSets(convertToJwkSet(ES256_KEYSET_TINK), ES256_JWK_SET_KID); } @Test public void convertRsaSsaPkcs1Keysets_success() throws Exception { assertEqualJwkSets(convertToJwkSet(RS256_KEYSET), RS256_JWK_SET); assertEqualJwkSets(convertToJwkSet(RS384_KEYSET), RS384_JWK_SET); assertEqualJwkSets(convertToJwkSet(RS512_KEYSET), RS512_JWK_SET); assertEqualJwkSets(convertToJwkSet(RS256_KEYSET_TINK), RS256_JWK_SET_KID); } @Test public void convertRsaSsaPssKeysets_success() throws Exception { assertEqualJwkSets(convertToJwkSet(PS256_KEYSET), PS256_JWK_SET); assertEqualJwkSets(convertToJwkSet(PS384_KEYSET), PS384_JWK_SET); assertEqualJwkSets(convertToJwkSet(PS512_KEYSET), PS512_JWK_SET); assertEqualJwkSets(convertToJwkSet(PS256_KEYSET_TINK), PS256_JWK_SET_KID); } @Test public void toPublicKeysetHandlefromPublicKeysetHandle_success() throws Exception { assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(ES256_JWK_SET)), ES256_JWK_SET); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(ES384_JWK_SET)), ES384_JWK_SET); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(ES512_JWK_SET)), ES512_JWK_SET); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(RS256_JWK_SET)), RS256_JWK_SET); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(RS384_JWK_SET)), RS384_JWK_SET); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(RS512_JWK_SET)), RS512_JWK_SET); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(PS256_JWK_SET)), PS256_JWK_SET); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(PS384_JWK_SET)), PS384_JWK_SET); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(JwkSetConverter.toPublicKeysetHandle(PS512_JWK_SET)), PS512_JWK_SET); } @Test public void toPublicKeysetHandleWithValidKid_fromPublicKeysetHandle_sameJwkSet() throws Exception { // When the kid can be decoded into a key ID, the output prefix type of the key will be TINK, // and the same kid value will be generated again when converted to JWK Set. assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle( JwkSetConverter.toPublicKeysetHandle(ES256_JWK_SET_KID)), ES256_JWK_SET_KID); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle( JwkSetConverter.toPublicKeysetHandle(RS256_JWK_SET_KID)), RS256_JWK_SET_KID); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle( JwkSetConverter.toPublicKeysetHandle(PS256_JWK_SET_KID)), PS256_JWK_SET_KID); } @Test public void jwkEs256WithKid_isImportedAsRaw() throws Exception { KeysetHandle converted = JwkSetConverter.toPublicKeysetHandle(ES256_JWK_SET_KID); KeysetHandle expected = TinkJsonProtoKeysetFormat.parseKeyset( ES256_JWK_SET_KID_TINK, InsecureSecretKeyAccess.get()); // The KeyID is picked at random, hence we just compare the keys. assertTrue(converted.getAt(0).getKey().equalsKey(expected.getAt(0).getKey())); } @Test public void jwkRs256WithKid_isImportedAsRaw() throws Exception { KeysetHandle converted = JwkSetConverter.toPublicKeysetHandle(RS256_JWK_SET_KID); KeysetHandle expected = TinkJsonProtoKeysetFormat.parseKeyset( RS256_JWK_SET_KID_TINK, InsecureSecretKeyAccess.get()); // The KeyID is picked at random, hence we just compare the keys. assertTrue(converted.getAt(0).getKey().equalsKey(expected.getAt(0).getKey())); } @Test public void jwkPs256WithKid_isImportedAsRaw() throws Exception { KeysetHandle converted = JwkSetConverter.toPublicKeysetHandle(PS256_JWK_SET_KID); KeysetHandle expected = TinkJsonProtoKeysetFormat.parseKeyset( PS256_JWK_SET_KID_TINK, InsecureSecretKeyAccess.get()); // The KeyID is picked at random, hence we just compare the keys. assertTrue(converted.getAt(0).getKey().equalsKey(expected.getAt(0).getKey())); } @Test public void jwkWithEmptyKid_kidIsPreserved() throws Exception { String esWithEmptyKid = ES256_JWK_SET_KID.replace("\"ENgjPA\"", "\"\""); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle( JwkSetConverter.toPublicKeysetHandle(esWithEmptyKid)), esWithEmptyKid); String rsWithEmptyKid = RS256_JWK_SET_KID.replace("\"HL1QoQ\"", "\"\""); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle( JwkSetConverter.toPublicKeysetHandle(rsWithEmptyKid)), rsWithEmptyKid); String psWithEmptyKid = PS256_JWK_SET_KID.replace("\"Wes4wg\"", "\"\""); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle( JwkSetConverter.toPublicKeysetHandle(psWithEmptyKid)), psWithEmptyKid); } @Test public void toPublicKeysetHandleSetsKeyIdsAndPrimaryKeyId() throws Exception { KeysetHandle handle = JwkSetConverter.toPublicKeysetHandle(JWK_SET_WITH_TWO_KEYS); assertThat(handle.size()).isEqualTo(2); assertThat(handle.getAt(0).getKey()).isInstanceOf(JwtEcdsaPublicKey.class); assertThat(handle.getAt(1).getKey()).isInstanceOf(JwtRsaSsaPkcs1PublicKey.class); } @DataPoints("templatesNames") public static final String[] TEMPLATE_NAMES = new String[] { "JWT_ES256", "JWT_ES384", "JWT_ES512", "JWT_ES256_RAW", "JWT_RS256_2048_F4", "JWT_RS256_3072_F4", "JWT_RS384_3072_F4", "JWT_RS512_4096_F4", "JWT_RS256_2048_F4_RAW", "JWT_PS256_2048_F4", "JWT_PS256_3072_F4", "JWT_PS384_3072_F4", "JWT_PS512_4096_F4", "JWT_PS256_2048_F4_RAW", }; @Theory public void convertTinkToJwksTokenVerification_success( @FromDataPoints("templatesNames") String templateName) throws Exception { if (TestUtil.isTsan()) { // KeysetHandle.generateNew is too slow in Tsan. return; } KeysetHandle keysetHandle = KeysetHandle.generateNew(KeyTemplates.get(templateName)); String jwksString = JwkSetConverter.fromPublicKeysetHandle(keysetHandle.getPublicKeysetHandle()); KeysetHandle publicKeysetHandle = JwkSetConverter.toPublicKeysetHandle(jwksString); JwtPublicKeySign signer = keysetHandle.getPrimitive(RegistryConfiguration.get(), JwtPublicKeySign.class); JwtPublicKeyVerify verifier = publicKeysetHandle.getPrimitive(RegistryConfiguration.get(), JwtPublicKeyVerify.class); RawJwt rawToken = RawJwt.newBuilder().setJwtId("jwtId").withoutExpiration().build(); String signedCompact = signer.signAndEncode(rawToken); JwtValidator validator = JwtValidator.newBuilder().allowMissingExpiration().build(); VerifiedJwt verifiedToken = verifier.verifyAndDecode(signedCompact, validator); assertThat(verifiedToken.getJwtId()).isEqualTo("jwtId"); } @Test public void keysetWithTwoKeys_fromPublicKeysetHandleSuccess() throws Exception { assertEqualJwkSets(convertToJwkSet(KEYSET_WITH_TWO_KEYS), JWK_SET_WITH_TWO_KEYS); } @Test public void primaryKeyIdMissing_fromPublicKeysetHandleSuccess() throws Exception { String keyset = ES256_KEYSET.replace("\"primaryKeyId\":282600252,", ""); assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset)); } @Test public void legacyEcdsaKeysets_fromPublicKeysetHandleFails() throws Exception { String keyset = ES256_KEYSET.replace("RAW", "LEGACY"); assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset)); } @Test public void crunchyEcdsaKeysets_fromPublicKeysetHandleFails() throws Exception { String keyset = ES256_KEYSET.replace("RAW", "CRUNCHY"); assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset)); } @Test public void privateKey_fromPublicKeysetHandleFails() throws Exception { assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(PRIVATEKEY_KEYSET)); } @Test public void legacyRsaSsaPkcs1Keysets_fromPublicKeysetHandleFails() throws Exception { String keyset = RS256_KEYSET.replace("RAW", "LEGACY"); assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset)); } @Test public void crunchyRsaSsaPkcs1Keysets_fromPublicKeysetHandleFails() throws Exception { String keyset = RS256_KEYSET.replace("RAW", "CRUNCHY"); assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset)); } @Test public void legacyRsaSsaPssKeysets_fromPublicKeysetHandleFails() throws Exception { String keyset = PS256_KEYSET.replace("RAW", "LEGACY"); assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset)); } @Test public void crunchyRsaSsaPssKeysets_fromPublicKeysetHandleFails() throws Exception { String keyset = PS256_KEYSET.replace("RAW", "CRUNCHY"); assertThrows(GeneralSecurityException.class, () -> convertToJwkSet(keyset)); } @Test public void fromPublicKeysetHandle_throwsOnInvalidKeysetHandle() throws Exception { Keyset keyset = Keyset.newBuilder() .setPrimaryKeyId(1) .addKey( Keyset.Key.newBuilder() .setKeyId(1) // Keysets with unknown status are not parsed properly and will throw unchecked // at getAt() .setStatus(KeyStatusType.UNKNOWN_STATUS) .setKeyData( KeyData.newBuilder() .setTypeUrl("somenonexistenttypeurl") .setKeyMaterialType(KeyMaterialType.ASYMMETRIC_PUBLIC) .setValue(ByteString.EMPTY))) .build(); KeysetHandle handle = TinkProtoKeysetFormat.parseKeysetWithoutSecret(keyset.toByteArray()); assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.fromPublicKeysetHandle(handle)); } @Test public void ecdsaWithoutUseAndKeyOps_toPublicKeysetHandleSuccess() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"alg\":\"ES256\"" + "}]}"; // ignore returned value, we only test that it worked. Object unused = JwkSetConverter.toPublicKeysetHandle(jwksString); } @Test public void ecdsaPrivateKey_fails() throws Exception { // Example from https://datatracker.ietf.org/doc/html/rfc7517#appendix-A.2 String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4\"," + "\"y\":\"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM\"," + "\"d\":\"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE\"," + "\"alg\":\"ES256\"" + "}]}"; assertThrows( UnsupportedOperationException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void ecdsaWithUnknownField_toPublicKeysetHandleSuccess() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"alg\":\"ES256\"," + "\"unknown\":1234," + "\"use\":\"sig\"," + "\"key_ops\":[\"verify\"]" + "}]}"; // ignore returned value, we only test that it worked. Object unused = JwkSetConverter.toPublicKeysetHandle(jwksString); } @Test public void ecdsaWithoutAlg_toPublicKeysetHandleFails() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"use\":\"sig\"," + "\"key_ops\":[\"verify\"]" + "}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void ecdsaWithoutKty_toPublicKeysetHandleFails() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"crv\":\"P-256\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"use\":\"sig\"," + "\"alg\":\"ES256\"," + "\"key_ops\":[\"verify\"]" + "}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void ecdsaWithoutCrv_toPublicKeysetHandleFails() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"use\":\"sig\"," + "\"alg\":\"ES256\"," + "\"key_ops\":[\"verify\"]" + "}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void ecdsa_pointNotOnCurve_getPrimitiveFails() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"AAAwOQ\"," + "\"use\":\"sig\"," + "\"alg\":\"ES256\"," + "\"key_ops\":[\"verify\"]" + "}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void ecdsaWithInvalidKty_toPublicKeysetHandleFails() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"RSA\"," + "\"crv\":\"P-256\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"use\":\"sig\"," + "\"alg\":\"ES256\"," + "\"key_ops\":[\"verify\"]" + "}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void ecdsaWithInvalidCrv_toPublicKeysetHandleFails() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-384\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"use\":\"sig\"," + "\"alg\":\"ES256\"," + "\"key_ops\":[\"verify\"]" + "}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void ecdsaWithInvalidUse_toPublicKeysetHandleFails() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"use\":\"invalid\"," + "\"alg\":\"ES256\"," + "\"key_ops\":[\"verify\"]" + "}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void ecdsaWithInvalidKeyOps_toPublicKeysetHandleFails() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"use\":\"sig\"," + "\"alg\":\"ES256\"," + "\"key_ops\":[\"invalid\"]" + "}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void ecdsaWithStringKeyOps_toPublicKeysetHandleFails() throws Exception { String jwksString = "{" + "\"keys\":[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"KUPydf4k4cS5EGS82npjEUxKIiBfUGP3wlN49A2GxTY\"," + "\"y\":\"b22m_Y4sT-jUJSxBVqjrW_DxWyBLopxYHTuFVfx70ZI\"," + "\"use\":\"sig\"," + "\"alg\":\"ES256\"," + "\"key_ops\":\"verify\"" + "}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void rsaWithoutUseAndKeyOps_toPublicKeysetHandleSuccess() throws Exception { String jwksString = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks" + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T" + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6" + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY" + "2oFr3AwKBYDHvsc\"," + "\"e\":\"AQAB\",\"alg\":\"RS256\"}]}"; // ignore returned value, we only test that it worked. Object unused = JwkSetConverter.toPublicKeysetHandle(jwksString); String psJwksString = jwksString.replace("RS256", "PS256"); // ignore returned value, we only test that it worked. unused = JwkSetConverter.toPublicKeysetHandle(psJwksString); } @Test public void rsaWithUnknownField_toPublicKeysetHandleSuccess() throws Exception { String jwksString = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks" + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T" + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6" + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY" + "2oFr3AwKBYDHvsc\"," + "\"unknown\":1234," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}"; // ignore returned value, we only test that it worked. Object unused = JwkSetConverter.toPublicKeysetHandle(jwksString); String psJwksString = jwksString.replace("RS256", "PS256"); // ignore returned value, we only test that it worked. unused = JwkSetConverter.toPublicKeysetHandle(psJwksString); } @Test public void rsaPrivateKey_fails() throws Exception { // Example from https://datatracker.ietf.org/doc/html/rfc7517#appendix-A.2 String jwksString = "{\"keys\":[" + "{\"kty\":\"RSA\"," + "\"n\":\"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4" + "cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMst" + "n64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2Q" + "vzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS" + "D08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw" + "0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\"," + "\"e\":\"AQAB\"," + "\"d\":\"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9" + "M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqij" + "wp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d" + "_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBz" + "nbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFz" + "me1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q\"," + "\"p\":\"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPV" + "nwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqV" + "WlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs\"," + "\"q\":\"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyum" + "qjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgx" + "kIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk\"," + "\"dp\":\"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oim" + "YwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_Nmtu" + "YZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0\"," + "\"dq\":\"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUU" + "vMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9" + "GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk\"," + "\"qi\":\"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzg" + "UIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rx" + "yR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU\"," + "\"alg\":\"RS256\"," + "\"kid\":\"2011-04-29\"}]}"; assertThrows( UnsupportedOperationException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); String psJwksString = jwksString.replace("RS256", "PS256"); assertThrows( UnsupportedOperationException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString)); } @Test public void rsaWithoutAlg_toPublicKeysetHandleFails() throws Exception { String jwksString = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks" + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T" + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6" + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY" + "2oFr3AwKBYDHvsc\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"key_ops\":[\"verify\"]}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); } @Test public void rsaWithoutKty_toPublicKeysetHandleFails() throws Exception { String jwksString = "{\"keys\":[{" + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks" + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T" + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6" + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY" + "2oFr3AwKBYDHvsc\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); String psJwksString = jwksString.replace("RS256", "PS256"); assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString)); } @Test public void rsaWithSmallN_getPrimitiveFails() throws Exception { String jwksString = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"AAAwOQ\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); String psJwksString = jwksString.replace("RS256", "PS256"); assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString)); } @Test public void rsaWithInvalidKty_toPublicKeysetHandleFails() throws Exception { String jwksString = "{\"keys\":[{\"kty\":\"EC\"," + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks" + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T" + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6" + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY" + "2oFr3AwKBYDHvsc\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); String psJwksString = jwksString.replace("RS256", "PS256"); assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString)); } @Test public void rsaWithInvalidUse_toPublicKeysetHandleFails() throws Exception { String jwksString = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks" + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T" + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6" + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY" + "2oFr3AwKBYDHvsc\"," + "\"e\":\"AQAB\",\"use\":\"invalid\",\"alg\":\"RS256\",\"key_ops\":[\"verify\"]}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); String psJwksString = jwksString.replace("RS256", "PS256"); assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString)); } @Test public void rsaWithInvalidKeyOps_toPublicKeysetHandleFails() throws Exception { String jwksString = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks" + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T" + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6" + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY" + "2oFr3AwKBYDHvsc\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":[\"invalid\"]}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); String psJwksString = jwksString.replace("RS256", "PS256"); assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString)); } @Test public void rsaWithStringKeyOps_toPublicKeysetHandleFails() throws Exception { String jwksString = "{\"keys\":[{\"kty\":\"RSA\"," + "\"n\":\"AM90NXQrAtt6KPSevzv9nbLJ2g_WPDH4zTwOo1slR8qC2chi6mH4TONOyAracdhQaoPwtMKge2ks" + "dJi1GaYwl975uvZEd9J1G078tlGrKPpy5I_OHseYDoeP8EgXawNII5ayFo-Ch_ZTxyzOuWmeb3DJft177D7T" + "Foz-zrMoTDGV4gwhBPeVfSk5DYvY06hF740KZq89nXBX_51KE5C-M9hBJMK9VA7BiGM8qjeu7l7ppXdzfvf6" + "azfkIogKMV7Xk0aw6nCW6h49BYuIu3TVjiToLEu5kX0z501whcCI8SA1tlicl7CzOCvVF70vg03RAB5vZQWY" + "2oFr3AwKBYDHvsc\"," + "\"e\":\"AQAB\",\"use\":\"sig\",\"alg\":\"RS256\",\"key_ops\":\"verify\"}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksString)); String psJwksString = jwksString.replace("RS256", "PS256"); assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(psJwksString)); } @Test public void jwksetWithDuplicateMapKey_fails() throws Exception { String jwkSetWithDuplicateMapKey = "{\"keys\":[{" + "\"kty\":\"EC\"," + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\"," + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\"," + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"]}]}"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwkSetWithDuplicateMapKey)); } @Test public void jwksetAsJsonArray_fails() throws Exception { String jwksetAsJsonArray = "[{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"EM8jrqGMse-PGZQnafIcgEOZ061DiA-y9aBhiBnSDKA\"," + "\"y\":\"UxCtK0wAqQG_e5vpr7SSgJNKt5h4z3FGZtAuBLng1uE\"," + "\"use\":\"sig\",\"alg\":\"ES256\",\"key_ops\":[\"verify\"]}]"; assertThrows( GeneralSecurityException.class, () -> JwkSetConverter.toPublicKeysetHandle(jwksetAsJsonArray)); } @Test @SuppressWarnings("InlineMeInliner") public void deprecatedFromKeysetHandle_sameAs_fromPublicKeysetHandle() throws Exception { KeysetHandle handle = TinkJsonProtoKeysetFormat.parseKeyset(ES256_KEYSET, InsecureSecretKeyAccess.get()); assertEqualJwkSets( JwkSetConverter.fromKeysetHandle(handle, KeyAccess.publicAccess()), JwkSetConverter.fromPublicKeysetHandle(handle)); } @Test @SuppressWarnings("InlineMeInliner") public void deprecatedToKeysetHandle_sameAs_toPublicKeysetHandle() throws Exception { KeysetHandle handle = JwkSetConverter.toPublicKeysetHandle(ES256_JWK_SET); KeysetHandle deprecatedHandle = JwkSetConverter.toKeysetHandle(ES256_JWK_SET, KeyAccess.publicAccess()); assertEqualJwkSets( JwkSetConverter.fromPublicKeysetHandle(handle), JwkSetConverter.fromPublicKeysetHandle(deprecatedHandle)); } }