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 com.google.crypto.tink.KeyStatus; 20 import com.google.crypto.tink.KeysetHandle; 21 import com.google.crypto.tink.internal.BigIntegerEncoding; 22 import com.google.crypto.tink.internal.MutableSerializationRegistry; 23 import com.google.crypto.tink.internal.ProtoKeySerialization; 24 import com.google.crypto.tink.proto.JwtEcdsaAlgorithm; 25 import com.google.crypto.tink.proto.JwtEcdsaPublicKey; 26 import com.google.crypto.tink.proto.JwtRsaSsaPkcs1Algorithm; 27 import com.google.crypto.tink.proto.JwtRsaSsaPkcs1PublicKey; 28 import com.google.crypto.tink.proto.JwtRsaSsaPssAlgorithm; 29 import com.google.crypto.tink.proto.JwtRsaSsaPssPublicKey; 30 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 31 import com.google.crypto.tink.proto.OutputPrefixType; 32 import com.google.crypto.tink.subtle.Base64; 33 import com.google.crypto.tink.tinkkey.KeyAccess; 34 import com.google.errorprone.annotations.InlineMe; 35 import com.google.gson.JsonArray; 36 import com.google.gson.JsonElement; 37 import com.google.gson.JsonObject; 38 import com.google.gson.JsonParseException; 39 import com.google.gson.internal.Streams; 40 import com.google.gson.stream.JsonReader; 41 import com.google.protobuf.ByteString; 42 import com.google.protobuf.ExtensionRegistryLite; 43 import com.google.protobuf.InvalidProtocolBufferException; 44 import java.io.IOException; 45 import java.io.StringReader; 46 import java.math.BigInteger; 47 import java.nio.ByteBuffer; 48 import java.security.GeneralSecurityException; 49 import java.util.Optional; 50 import javax.annotation.Nullable; 51 52 /** 53 * Provides functions to import and export public Json Web Key (JWK) sets. 54 * 55 * <p>The currently supported algorithms are ES256, ES384, ES512, RS256, RS384, RS512, PS256, PS384 56 * and PS512. 57 */ 58 public final class JwkSetConverter { 59 60 /** 61 * Converts a Tink KeysetHandle with JWT public keys into a Json Web Key (JWK) set. 62 * 63 * <p>The currently supported algorithms are ES256, ES384, ES512, RS256, RS384, RS512, PS256, 64 * PS384 and PS512. JWK is defined in https://www.rfc-editor.org/rfc/rfc7517.txt. 65 */ fromPublicKeysetHandle(KeysetHandle handle)66 public static String fromPublicKeysetHandle(KeysetHandle handle) 67 throws IOException, GeneralSecurityException { 68 // Check validity of the keyset handle before calling "getAt". 69 // See comments in {@link KeysetHandle#Entry#getAt}. 70 handle = KeysetHandle.newBuilder(handle).build(); 71 // We never throw a IOException anymore, but keep it in the interface for compatibility. 72 JsonArray keys = new JsonArray(); 73 for (int i = 0; i < handle.size(); i++) { 74 KeysetHandle.Entry entry = handle.getAt(i); 75 if (entry.getStatus() != KeyStatus.ENABLED) { 76 continue; 77 } 78 ProtoKeySerialization protoKeySerialization = 79 MutableSerializationRegistry.globalInstance() 80 .serializeKey(entry.getKey(), ProtoKeySerialization.class, /* access= */ null); 81 82 if ((protoKeySerialization.getOutputPrefixType() != OutputPrefixType.RAW) 83 && (protoKeySerialization.getOutputPrefixType() != OutputPrefixType.TINK)) { 84 throw new GeneralSecurityException("only OutputPrefixType RAW and TINK are supported"); 85 } 86 if (protoKeySerialization.getKeyMaterialType() != KeyMaterialType.ASYMMETRIC_PUBLIC) { 87 throw new GeneralSecurityException("only public keys can be converted"); 88 } 89 switch (protoKeySerialization.getTypeUrl()) { 90 case JWT_ECDSA_PUBLIC_KEY_URL: 91 keys.add(convertJwtEcdsaKey(protoKeySerialization)); 92 break; 93 case JWT_RSA_SSA_PKCS1_PUBLIC_KEY_URL: 94 keys.add(convertJwtRsaSsaPkcs1(protoKeySerialization)); 95 break; 96 case JWT_RSA_SSA_PSS_PUBLIC_KEY_URL: 97 keys.add(convertJwtRsaSsaPss(protoKeySerialization)); 98 break; 99 default: 100 throw new GeneralSecurityException( 101 String.format("key type %s is not supported", protoKeySerialization.getTypeUrl())); 102 } 103 } 104 JsonObject jwkSet = new JsonObject(); 105 jwkSet.add("keys", keys); 106 return jwkSet.toString(); 107 } 108 109 /** 110 * Converts a Json Web Key (JWK) set with public keys into a Tink KeysetHandle. 111 * 112 * <p>It requires that all keys in the set have the "alg" field set. The currently supported 113 * algorithms are ES256, ES384, ES512, RS256, RS384, RS512, PS256, PS384 and PS512. JWK is defined 114 * in https://www.rfc-editor.org/rfc/rfc7517.txt. 115 */ toPublicKeysetHandle(String jwkSet)116 public static KeysetHandle toPublicKeysetHandle(String jwkSet) 117 throws IOException, GeneralSecurityException { 118 // We never throw a IOException anymore, but keep it in the interface for compatibility. 119 JsonObject jsonKeyset; 120 try { 121 JsonReader jsonReader = new JsonReader(new StringReader(jwkSet)); 122 jsonReader.setLenient(false); 123 jsonKeyset = Streams.parse(jsonReader).getAsJsonObject(); 124 } catch (IllegalStateException | JsonParseException | StackOverflowError ex) { 125 throw new GeneralSecurityException("JWK set is invalid JSON", ex); 126 } 127 KeysetHandle.Builder builder = KeysetHandle.newBuilder(); 128 JsonArray jsonKeys = jsonKeyset.get("keys").getAsJsonArray(); 129 for (JsonElement element : jsonKeys) { 130 JsonObject jsonKey = element.getAsJsonObject(); 131 String algPrefix = getStringItem(jsonKey, "alg").substring(0, 2); 132 ProtoKeySerialization keySerialization; 133 switch (algPrefix) { 134 case "RS": 135 keySerialization = convertToRsaSsaPkcs1Key(jsonKey); 136 break; 137 case "PS": 138 keySerialization = convertToRsaSsaPssKey(jsonKey); 139 break; 140 case "ES": 141 keySerialization = convertToEcdsaKey(jsonKey); 142 break; 143 default: 144 throw new GeneralSecurityException( 145 "unexpected alg value: " + getStringItem(jsonKey, "alg")); 146 } 147 builder.addEntry( 148 KeysetHandle.importKey( 149 MutableSerializationRegistry.globalInstance() 150 .parseKeyWithLegacyFallback(keySerialization, null)) 151 .withRandomId()); 152 } 153 if (builder.size() <= 0) { 154 throw new GeneralSecurityException("empty keyset"); 155 } 156 builder.getAt(0).makePrimary(); 157 return builder.build(); 158 } 159 160 private static final String JWT_ECDSA_PUBLIC_KEY_URL = 161 "type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey"; 162 private static final String JWT_RSA_SSA_PKCS1_PUBLIC_KEY_URL = 163 "type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey"; 164 private static final String JWT_RSA_SSA_PSS_PUBLIC_KEY_URL = 165 "type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey"; 166 getKid(@ullable Integer idRequirement)167 private static Optional<String> getKid(@Nullable Integer idRequirement) { 168 if (idRequirement == null) { 169 return Optional.empty(); 170 } 171 byte[] bigEndianKeyId = ByteBuffer.allocate(4).putInt(idRequirement).array(); 172 return Optional.of(Base64.urlSafeEncode(bigEndianKeyId)); 173 } 174 convertJwtEcdsaKey(ProtoKeySerialization protoKeySerialization)175 private static JsonObject convertJwtEcdsaKey(ProtoKeySerialization protoKeySerialization) 176 throws GeneralSecurityException { 177 JwtEcdsaPublicKey jwtEcdsaPublicKey; 178 try { 179 jwtEcdsaPublicKey = 180 JwtEcdsaPublicKey.parseFrom( 181 protoKeySerialization.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 182 } catch (InvalidProtocolBufferException e) { 183 throw new GeneralSecurityException("failed to parse value as JwtEcdsaPublicKey proto", e); 184 } 185 String alg; 186 String crv; 187 // We currently encode with one extra 0 byte at the beginning, to make sure 188 // that parsing is correct even if passing of a two's complement encoding is used. 189 // See also b/264525021. 190 int encLength; 191 switch (jwtEcdsaPublicKey.getAlgorithm()) { 192 case ES256: 193 alg = "ES256"; 194 crv = "P-256"; 195 encLength = 33; 196 break; 197 case ES384: 198 alg = "ES384"; 199 crv = "P-384"; 200 encLength = 49; 201 break; 202 case ES512: 203 alg = "ES512"; 204 crv = "P-521"; 205 encLength = 67; 206 break; 207 default: 208 throw new GeneralSecurityException("unknown algorithm"); 209 } 210 JsonObject jsonKey = new JsonObject(); 211 jsonKey.addProperty("kty", "EC"); 212 jsonKey.addProperty("crv", crv); 213 BigInteger x = 214 BigIntegerEncoding.fromUnsignedBigEndianBytes(jwtEcdsaPublicKey.getX().toByteArray()); 215 BigInteger y = 216 BigIntegerEncoding.fromUnsignedBigEndianBytes(jwtEcdsaPublicKey.getY().toByteArray()); 217 jsonKey.addProperty( 218 "x", Base64.urlSafeEncode(BigIntegerEncoding.toBigEndianBytesOfFixedLength(x, encLength))); 219 jsonKey.addProperty( 220 "y", Base64.urlSafeEncode(BigIntegerEncoding.toBigEndianBytesOfFixedLength(y, encLength))); 221 jsonKey.addProperty("use", "sig"); 222 jsonKey.addProperty("alg", alg); 223 JsonArray keyOps = new JsonArray(); 224 keyOps.add("verify"); 225 jsonKey.add("key_ops", keyOps); 226 Optional<String> kid = getKid(protoKeySerialization.getIdRequirementOrNull()); 227 if (kid.isPresent()) { 228 jsonKey.addProperty("kid", kid.get()); 229 } else if (jwtEcdsaPublicKey.hasCustomKid()) { 230 jsonKey.addProperty("kid", jwtEcdsaPublicKey.getCustomKid().getValue()); 231 } 232 return jsonKey; 233 } 234 convertJwtRsaSsaPkcs1(ProtoKeySerialization protoKeySerialization)235 private static JsonObject convertJwtRsaSsaPkcs1(ProtoKeySerialization protoKeySerialization) 236 throws GeneralSecurityException { 237 JwtRsaSsaPkcs1PublicKey jwtRsaSsaPkcs1PublicKey; 238 try { 239 jwtRsaSsaPkcs1PublicKey = 240 JwtRsaSsaPkcs1PublicKey.parseFrom( 241 protoKeySerialization.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 242 } catch (InvalidProtocolBufferException e) { 243 throw new GeneralSecurityException( 244 "failed to parse value as JwtRsaSsaPkcs1PublicKey proto", e); 245 } 246 String alg; 247 switch (jwtRsaSsaPkcs1PublicKey.getAlgorithm()) { 248 case RS256: 249 alg = "RS256"; 250 break; 251 case RS384: 252 alg = "RS384"; 253 break; 254 case RS512: 255 alg = "RS512"; 256 break; 257 default: 258 throw new GeneralSecurityException("unknown algorithm"); 259 } 260 JsonObject jsonKey = new JsonObject(); 261 jsonKey.addProperty("kty", "RSA"); 262 jsonKey.addProperty("n", Base64.urlSafeEncode(jwtRsaSsaPkcs1PublicKey.getN().toByteArray())); 263 jsonKey.addProperty("e", Base64.urlSafeEncode(jwtRsaSsaPkcs1PublicKey.getE().toByteArray())); 264 jsonKey.addProperty("use", "sig"); 265 jsonKey.addProperty("alg", alg); 266 JsonArray keyOps = new JsonArray(); 267 keyOps.add("verify"); 268 jsonKey.add("key_ops", keyOps); 269 Optional<String> kid = getKid(protoKeySerialization.getIdRequirementOrNull()); 270 if (kid.isPresent()) { 271 jsonKey.addProperty("kid", kid.get()); 272 } else if (jwtRsaSsaPkcs1PublicKey.hasCustomKid()) { 273 jsonKey.addProperty("kid", jwtRsaSsaPkcs1PublicKey.getCustomKid().getValue()); 274 } 275 return jsonKey; 276 } 277 convertJwtRsaSsaPss(ProtoKeySerialization protoKeySerialization)278 private static JsonObject convertJwtRsaSsaPss(ProtoKeySerialization protoKeySerialization) 279 throws GeneralSecurityException { 280 JwtRsaSsaPssPublicKey jwtRsaSsaPssPublicKey; 281 try { 282 jwtRsaSsaPssPublicKey = 283 JwtRsaSsaPssPublicKey.parseFrom( 284 protoKeySerialization.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 285 } catch (InvalidProtocolBufferException e) { 286 throw new GeneralSecurityException("failed to parse value as JwtRsaSsaPssPublicKey proto", e); 287 } 288 String alg; 289 switch (jwtRsaSsaPssPublicKey.getAlgorithm()) { 290 case PS256: 291 alg = "PS256"; 292 break; 293 case PS384: 294 alg = "PS384"; 295 break; 296 case PS512: 297 alg = "PS512"; 298 break; 299 default: 300 throw new GeneralSecurityException("unknown algorithm"); 301 } 302 JsonObject jsonKey = new JsonObject(); 303 jsonKey.addProperty("kty", "RSA"); 304 jsonKey.addProperty("n", Base64.urlSafeEncode(jwtRsaSsaPssPublicKey.getN().toByteArray())); 305 jsonKey.addProperty("e", Base64.urlSafeEncode(jwtRsaSsaPssPublicKey.getE().toByteArray())); 306 jsonKey.addProperty("use", "sig"); 307 jsonKey.addProperty("alg", alg); 308 JsonArray keyOps = new JsonArray(); 309 keyOps.add("verify"); 310 jsonKey.add("key_ops", keyOps); 311 Optional<String> kid = getKid(protoKeySerialization.getIdRequirementOrNull()); 312 if (kid.isPresent()) { 313 jsonKey.addProperty("kid", kid.get()); 314 } else if (jwtRsaSsaPssPublicKey.hasCustomKid()) { 315 jsonKey.addProperty("kid", jwtRsaSsaPssPublicKey.getCustomKid().getValue()); 316 } 317 return jsonKey; 318 } 319 getStringItem(JsonObject obj, String name)320 private static String getStringItem(JsonObject obj, String name) throws GeneralSecurityException { 321 if (!obj.has(name)) { 322 throw new GeneralSecurityException(name + " not found"); 323 } 324 if (!obj.get(name).isJsonPrimitive() || !obj.get(name).getAsJsonPrimitive().isString()) { 325 throw new GeneralSecurityException(name + " is not a string"); 326 } 327 return obj.get(name).getAsString(); 328 } 329 expectStringItem(JsonObject obj, String name, String expectedValue)330 private static void expectStringItem(JsonObject obj, String name, String expectedValue) 331 throws GeneralSecurityException { 332 String value = getStringItem(obj, name); 333 if (!value.equals(expectedValue)) { 334 throw new GeneralSecurityException("unexpected " + name + " value: " + value); 335 } 336 } 337 validateUseIsSig(JsonObject jsonKey)338 private static void validateUseIsSig(JsonObject jsonKey) throws GeneralSecurityException { 339 if (!jsonKey.has("use")) { 340 return; 341 } 342 expectStringItem(jsonKey, "use", "sig"); 343 } 344 validateKeyOpsIsVerify(JsonObject jsonKey)345 private static void validateKeyOpsIsVerify(JsonObject jsonKey) throws GeneralSecurityException { 346 if (!jsonKey.has("key_ops")) { 347 return; 348 } 349 if (!jsonKey.get("key_ops").isJsonArray()) { 350 throw new GeneralSecurityException("key_ops is not an array"); 351 } 352 JsonArray keyOps = jsonKey.get("key_ops").getAsJsonArray(); 353 if (keyOps.size() != 1) { 354 throw new GeneralSecurityException("key_ops must contain exactly one element"); 355 } 356 if (!keyOps.get(0).isJsonPrimitive() || !keyOps.get(0).getAsJsonPrimitive().isString()) { 357 throw new GeneralSecurityException("key_ops is not a string"); 358 } 359 if (!keyOps.get(0).getAsString().equals("verify")) { 360 throw new GeneralSecurityException("unexpected keyOps value: " + keyOps.get(0).getAsString()); 361 } 362 } 363 convertToRsaSsaPkcs1Key(JsonObject jsonKey)364 private static ProtoKeySerialization convertToRsaSsaPkcs1Key(JsonObject jsonKey) 365 throws GeneralSecurityException { 366 JwtRsaSsaPkcs1Algorithm algorithm; 367 switch (getStringItem(jsonKey, "alg")) { 368 case "RS256": 369 algorithm = JwtRsaSsaPkcs1Algorithm.RS256; 370 break; 371 case "RS384": 372 algorithm = JwtRsaSsaPkcs1Algorithm.RS384; 373 break; 374 case "RS512": 375 algorithm = JwtRsaSsaPkcs1Algorithm.RS512; 376 break; 377 default: 378 throw new GeneralSecurityException( 379 "Unknown Rsa Algorithm: " + getStringItem(jsonKey, "alg")); 380 } 381 if (jsonKey.has("p") 382 || jsonKey.has("q") 383 || jsonKey.has("dp") 384 || jsonKey.has("dq") 385 || jsonKey.has("d") 386 || jsonKey.has("qi")) { 387 throw new UnsupportedOperationException("importing RSA private keys is not implemented"); 388 } 389 expectStringItem(jsonKey, "kty", "RSA"); 390 validateUseIsSig(jsonKey); 391 validateKeyOpsIsVerify(jsonKey); 392 JwtRsaSsaPkcs1PublicKey.Builder pkcs1PubKeyBuilder = 393 JwtRsaSsaPkcs1PublicKey.newBuilder() 394 .setVersion(0) 395 .setAlgorithm(algorithm) 396 .setE(ByteString.copyFrom(Base64.urlSafeDecode(getStringItem(jsonKey, "e")))) 397 .setN(ByteString.copyFrom(Base64.urlSafeDecode(getStringItem(jsonKey, "n")))); 398 if (jsonKey.has("kid")) { 399 pkcs1PubKeyBuilder.setCustomKid( 400 JwtRsaSsaPkcs1PublicKey.CustomKid.newBuilder() 401 .setValue(getStringItem(jsonKey, "kid")) 402 .build()); 403 } 404 return ProtoKeySerialization.create( 405 JWT_RSA_SSA_PKCS1_PUBLIC_KEY_URL, 406 pkcs1PubKeyBuilder.build().toByteString(), 407 KeyMaterialType.ASYMMETRIC_PUBLIC, 408 OutputPrefixType.RAW, 409 null); 410 } 411 convertToRsaSsaPssKey(JsonObject jsonKey)412 private static ProtoKeySerialization convertToRsaSsaPssKey(JsonObject jsonKey) 413 throws GeneralSecurityException { 414 JwtRsaSsaPssAlgorithm algorithm; 415 switch (getStringItem(jsonKey, "alg")) { 416 case "PS256": 417 algorithm = JwtRsaSsaPssAlgorithm.PS256; 418 break; 419 case "PS384": 420 algorithm = JwtRsaSsaPssAlgorithm.PS384; 421 break; 422 case "PS512": 423 algorithm = JwtRsaSsaPssAlgorithm.PS512; 424 break; 425 default: 426 throw new GeneralSecurityException( 427 "Unknown Rsa Algorithm: " + getStringItem(jsonKey, "alg")); 428 } 429 if (jsonKey.has("p") 430 || jsonKey.has("q") 431 || jsonKey.has("dq") 432 || jsonKey.has("dq") 433 || jsonKey.has("d") 434 || jsonKey.has("qi")) { 435 throw new UnsupportedOperationException("importing RSA private keys is not implemented"); 436 } 437 expectStringItem(jsonKey, "kty", "RSA"); 438 validateUseIsSig(jsonKey); 439 validateKeyOpsIsVerify(jsonKey); 440 JwtRsaSsaPssPublicKey.Builder pssPubKeyBuilder = 441 JwtRsaSsaPssPublicKey.newBuilder() 442 .setVersion(0) 443 .setAlgorithm(algorithm) 444 .setE(ByteString.copyFrom(Base64.urlSafeDecode(getStringItem(jsonKey, "e")))) 445 .setN(ByteString.copyFrom(Base64.urlSafeDecode(getStringItem(jsonKey, "n")))); 446 if (jsonKey.has("kid")) { 447 pssPubKeyBuilder.setCustomKid( 448 JwtRsaSsaPssPublicKey.CustomKid.newBuilder() 449 .setValue(getStringItem(jsonKey, "kid")) 450 .build()); 451 } 452 return ProtoKeySerialization.create( 453 JWT_RSA_SSA_PSS_PUBLIC_KEY_URL, 454 pssPubKeyBuilder.build().toByteString(), 455 KeyMaterialType.ASYMMETRIC_PUBLIC, 456 OutputPrefixType.RAW, 457 null); 458 } 459 convertToEcdsaKey(JsonObject jsonKey)460 private static ProtoKeySerialization convertToEcdsaKey(JsonObject jsonKey) 461 throws GeneralSecurityException { 462 JwtEcdsaAlgorithm algorithm; 463 switch (getStringItem(jsonKey, "alg")) { 464 case "ES256": 465 expectStringItem(jsonKey, "crv", "P-256"); 466 algorithm = JwtEcdsaAlgorithm.ES256; 467 break; 468 case "ES384": 469 expectStringItem(jsonKey, "crv", "P-384"); 470 algorithm = JwtEcdsaAlgorithm.ES384; 471 break; 472 case "ES512": 473 expectStringItem(jsonKey, "crv", "P-521"); 474 algorithm = JwtEcdsaAlgorithm.ES512; 475 break; 476 default: 477 throw new GeneralSecurityException( 478 "Unknown Ecdsa Algorithm: " + getStringItem(jsonKey, "alg")); 479 } 480 if (jsonKey.has("d")) { 481 throw new UnsupportedOperationException("importing ECDSA private keys is not implemented"); 482 } 483 expectStringItem(jsonKey, "kty", "EC"); 484 validateUseIsSig(jsonKey); 485 validateKeyOpsIsVerify(jsonKey); 486 JwtEcdsaPublicKey.Builder ecdsaPubKeyBuilder = 487 JwtEcdsaPublicKey.newBuilder() 488 .setVersion(0) 489 .setAlgorithm(algorithm) 490 .setX(ByteString.copyFrom(Base64.urlSafeDecode(getStringItem(jsonKey, "x")))) 491 .setY(ByteString.copyFrom(Base64.urlSafeDecode(getStringItem(jsonKey, "y")))); 492 if (jsonKey.has("kid")) { 493 ecdsaPubKeyBuilder.setCustomKid( 494 JwtEcdsaPublicKey.CustomKid.newBuilder().setValue(getStringItem(jsonKey, "kid")).build()); 495 } 496 return ProtoKeySerialization.create( 497 JWT_ECDSA_PUBLIC_KEY_URL, 498 ecdsaPubKeyBuilder.build().toByteString(), 499 KeyMaterialType.ASYMMETRIC_PUBLIC, 500 OutputPrefixType.RAW, 501 null); 502 } 503 504 /** 505 * @deprecated Use JwkSetConverter.fromPublicKeysetHandle(handle) instead. 506 */ 507 @InlineMe( 508 replacement = "JwkSetConverter.fromPublicKeysetHandle(handle)", 509 imports = "com.google.crypto.tink.jwt.JwkSetConverter") 510 @Deprecated fromKeysetHandle(KeysetHandle handle, KeyAccess keyAccess)511 public static String fromKeysetHandle(KeysetHandle handle, KeyAccess keyAccess) 512 throws IOException, GeneralSecurityException { 513 return fromPublicKeysetHandle(handle); 514 } 515 516 /** 517 * @deprecated Use JwkSetConverter.toPublicKeysetHandle(jwkSet) instead. 518 */ 519 @InlineMe( 520 replacement = "JwkSetConverter.toPublicKeysetHandle(jwkSet)", 521 imports = "com.google.crypto.tink.jwt.JwkSetConverter") 522 @Deprecated toKeysetHandle(String jwkSet, KeyAccess keyAccess)523 public static KeysetHandle toKeysetHandle(String jwkSet, KeyAccess keyAccess) 524 throws IOException, GeneralSecurityException { 525 return toPublicKeysetHandle(jwkSet); 526 } 527 JwkSetConverter()528 private JwkSetConverter() {} 529 } 530