// 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.signature;

import com.google.crypto.tink.proto.EcdsaParams;
import com.google.crypto.tink.proto.EcdsaSignatureEncoding;
import com.google.crypto.tink.proto.EllipticCurveType;
import com.google.crypto.tink.proto.HashType;
import com.google.crypto.tink.proto.RsaSsaPkcs1Params;
import com.google.crypto.tink.proto.RsaSsaPssParams;
import com.google.crypto.tink.subtle.EllipticCurves;
import com.google.crypto.tink.subtle.Enums;
import java.security.GeneralSecurityException;

final class SigUtil {
  static final String INVALID_PARAMS = "Invalid ECDSA parameters";

  
Validates Ecdsa's parameters. The hash's strength must not be weaker than the curve's strength.
Params:
  • params – the Ecdsa's parameters protocol buffer.
Throws:
/** * Validates Ecdsa's parameters. The hash's strength must not be weaker than the curve's strength. * * @param params the Ecdsa's parameters protocol buffer. * @throws GeneralSecurityException iff it's invalid. */
public static void validateEcdsaParams(EcdsaParams params) throws GeneralSecurityException { EcdsaSignatureEncoding encoding = params.getEncoding(); HashType hash = params.getHashType(); EllipticCurveType curve = params.getCurve(); switch (encoding) { case DER: // fall through case IEEE_P1363: break; default: throw new GeneralSecurityException("unsupported signature encoding"); } switch (curve) { case NIST_P256: // Using SHA512 for curve P256 is fine. However, only the 256 leftmost bits of the hash is // used in signature computation. Therefore, we don't allow it here to prevent security // illusion. if (hash != HashType.SHA256) { throw new GeneralSecurityException(INVALID_PARAMS); } break; case NIST_P384: if (hash != HashType.SHA384 && hash != HashType.SHA512) { throw new GeneralSecurityException(INVALID_PARAMS); } break; case NIST_P521: if (hash != HashType.SHA512) { throw new GeneralSecurityException(INVALID_PARAMS); } break; default: throw new GeneralSecurityException(INVALID_PARAMS); } }
Validates RsaSsaPkcs1's parameters. As SHA1 is unsafe, we will only support SHA256 and SHA512 for digital signature.
Params:
  • params – the RsaSsaPkcs1Params protocol buffer.
Throws:
/** * Validates RsaSsaPkcs1's parameters. As SHA1 is unsafe, we will only support SHA256 and SHA512 * for digital signature. * * @param params the RsaSsaPkcs1Params protocol buffer. * @throws GeneralSecurityException iff it's invalid. */
public static void validateRsaSsaPkcs1Params(RsaSsaPkcs1Params params) throws GeneralSecurityException { toHashType(params.getHashType()); }
Validates RsaSsaPss's parameters.
  • As SHA1 is unsafe, we will only support SHA256 and SHA512 for digital signature.
  • The most common use case is that MGF1 hash is the same as signature hash. This is recommended by RFC https://tools.ietf.org/html/rfc8017#section-8.1. While using different hashes doesn't cause security vulnerabilities, there is also no good reason to support different hashes. Furthermore:
    • Golang does not support different hashes.
    • BoringSSL supports different hashes just because of historical reason. There is no real use case.
    • Conscrypt/BouncyCastle do not support different hashes.
Params:
  • params – the RsaSsaPssParams protocol buffer.
Throws:
/** * Validates RsaSsaPss's parameters. * * <ul> * <li>As SHA1 is unsafe, we will only support SHA256 and SHA512 for digital signature. * <li>The most common use case is that MGF1 hash is the same as signature hash. This is * recommended by RFC https://tools.ietf.org/html/rfc8017#section-8.1. While using different * hashes doesn't cause security vulnerabilities, there is also no good reason to support * different hashes. Furthermore: * <ul> * <li>Golang does not support different hashes. * <li>BoringSSL supports different hashes just because of historical reason. There is no * real use case. * <li>Conscrypt/BouncyCastle do not support different hashes. * </ul> * </ul> * * @param params the RsaSsaPssParams protocol buffer. * @throws GeneralSecurityException iff it's invalid. */
public static void validateRsaSsaPssParams(RsaSsaPssParams params) throws GeneralSecurityException { toHashType(params.getSigHash()); if (params.getSigHash() != params.getMgf1Hash()) { throw new GeneralSecurityException("MGF1 hash is different from signature hash"); } }
Converts protobuf enum HashType to raw Java enum Enums.HashType.
/** Converts protobuf enum {@code HashType} to raw Java enum {@code Enums.HashType}. */
public static Enums.HashType toHashType(HashType hash) throws GeneralSecurityException { switch (hash) { case SHA256: return Enums.HashType.SHA256; case SHA384: return Enums.HashType.SHA384; case SHA512: return Enums.HashType.SHA512; default: break; } throw new GeneralSecurityException("unsupported hash type: " + hash.name()); }
Converts protobuf enum EllipticCurveType to raw Java enum {code CurveType}.
/** Converts protobuf enum {@code EllipticCurveType} to raw Java enum {code CurveType}. */
public static EllipticCurves.CurveType toCurveType(EllipticCurveType type) throws GeneralSecurityException { switch (type) { case NIST_P256: return EllipticCurves.CurveType.NIST_P256; case NIST_P384: return EllipticCurves.CurveType.NIST_P384; case NIST_P521: return EllipticCurves.CurveType.NIST_P521; default: throw new GeneralSecurityException("unknown curve type: " + type); } }
Converts protobuf enum EcdsaSignatureEncoding to raw Java enum {code EllipticCurves.EcdsaEncoding}.
/** * Converts protobuf enum {@code EcdsaSignatureEncoding} to raw Java enum {code * EllipticCurves.EcdsaEncoding}. */
public static EllipticCurves.EcdsaEncoding toEcdsaEncoding(EcdsaSignatureEncoding encoding) throws GeneralSecurityException { switch (encoding) { case IEEE_P1363: return EllipticCurves.EcdsaEncoding.IEEE_P1363; case DER: return EllipticCurves.EcdsaEncoding.DER; default: throw new GeneralSecurityException("unknown ECDSA encoding: " + encoding); } } }