blob: ccd5597c7ae35375763caf838053047e4838eaa2 [file] [log] [blame]
// Copyright 2017 Google Inc.
//
// 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 java.nio.charset.StandardCharsets.US_ASCII;
import com.google.crypto.tink.internal.KeyTypeManager;
import com.google.crypto.tink.internal.PrimitiveFactory;
import com.google.crypto.tink.proto.JwtEcdsaAlgorithm;
import com.google.crypto.tink.proto.JwtEcdsaPublicKey;
import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
import com.google.crypto.tink.subtle.EcdsaVerifyJce;
import com.google.crypto.tink.subtle.EllipticCurves;
import com.google.crypto.tink.subtle.EllipticCurves.EcdsaEncoding;
import com.google.crypto.tink.subtle.Enums;
import com.google.crypto.tink.subtle.Validators;
import com.google.gson.JsonObject;
import com.google.protobuf.ByteString;
import com.google.protobuf.ExtensionRegistryLite;
import com.google.protobuf.InvalidProtocolBufferException;
import java.security.GeneralSecurityException;
import java.security.interfaces.ECPublicKey;
import java.util.Optional;
/**
* This key manager produces new instances of {@code JwtEcdsaVerify}. It doesn't support key
* generation.
*/
class JwtEcdsaVerifyKeyManager extends KeyTypeManager<JwtEcdsaPublicKey> {
static final EllipticCurves.CurveType getCurve(JwtEcdsaAlgorithm algorithm)
throws GeneralSecurityException {
switch (algorithm) {
case ES256:
return EllipticCurves.CurveType.NIST_P256;
case ES384:
return EllipticCurves.CurveType.NIST_P384;
case ES512:
return EllipticCurves.CurveType.NIST_P521;
default:
throw new GeneralSecurityException("unknown algorithm " + algorithm.name());
}
}
public static Enums.HashType hashForEcdsaAlgorithm(JwtEcdsaAlgorithm algorithm)
throws GeneralSecurityException {
switch (algorithm) {
case ES256:
return Enums.HashType.SHA256;
case ES384:
return Enums.HashType.SHA384;
case ES512:
return Enums.HashType.SHA512;
default:
throw new GeneralSecurityException("unknown algorithm " + algorithm.name());
}
}
static final void validateEcdsaAlgorithm(JwtEcdsaAlgorithm algorithm)
throws GeneralSecurityException {
// Purposely ignore the result. This function will throw if the algorithm is invalid.
hashForEcdsaAlgorithm(algorithm);
}
private static class JwtPublicKeyVerifyFactory
extends PrimitiveFactory<JwtPublicKeyVerifyInternal, JwtEcdsaPublicKey> {
public JwtPublicKeyVerifyFactory() {
super(JwtPublicKeyVerifyInternal.class);
}
@Override
public JwtPublicKeyVerifyInternal getPrimitive(JwtEcdsaPublicKey keyProto)
throws GeneralSecurityException {
// This will throw an exception is protocol is invalid
EllipticCurves.CurveType curve = getCurve(keyProto.getAlgorithm());
ECPublicKey publicKey =
EllipticCurves.getEcPublicKey(
curve, keyProto.getX().toByteArray(), keyProto.getY().toByteArray());
Enums.HashType hash = hashForEcdsaAlgorithm(keyProto.getAlgorithm());
final EcdsaVerifyJce verifier = new EcdsaVerifyJce(publicKey, hash, EcdsaEncoding.IEEE_P1363);
final String algorithmName = keyProto.getAlgorithm().name();
final Optional<String> customKidFromEcdsaPublicKey =
keyProto.hasCustomKid()
? Optional.of(keyProto.getCustomKid().getValue())
: Optional.empty();
return new JwtPublicKeyVerifyInternal() {
@Override
public VerifiedJwt verifyAndDecodeWithKid(
String compact, JwtValidator validator, Optional<String> kid)
throws GeneralSecurityException {
JwtFormat.Parts parts = JwtFormat.splitSignedCompact(compact);
verifier.verify(parts.signatureOrMac, parts.unsignedCompact.getBytes(US_ASCII));
JsonObject parsedHeader = JsonUtil.parseJson(parts.header);
JwtFormat.validateHeader(algorithmName, kid, customKidFromEcdsaPublicKey, parsedHeader);
RawJwt token =
RawJwt.fromJsonPayload(JwtFormat.getTypeHeader(parsedHeader), parts.payload);
return validator.validate(token);
}
};
}
}
public JwtEcdsaVerifyKeyManager() {
super(JwtEcdsaPublicKey.class, new JwtPublicKeyVerifyFactory());
}
@Override
public String getKeyType() {
return "type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey";
}
@Override
public int getVersion() {
return 0;
}
@Override
public KeyMaterialType keyMaterialType() {
return KeyMaterialType.ASYMMETRIC_PUBLIC;
}
@Override
public JwtEcdsaPublicKey parseKey(ByteString byteString) throws InvalidProtocolBufferException {
return JwtEcdsaPublicKey.parseFrom(byteString, ExtensionRegistryLite.getEmptyRegistry());
}
@Override
public void validateKey(JwtEcdsaPublicKey pubKey) throws GeneralSecurityException {
Validators.validateVersion(pubKey.getVersion(), getVersion());
validateEcdsaAlgorithm(pubKey.getAlgorithm());
}
}