1 // Copyright 2017 Google Inc. 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.signature; 18 19 import static com.google.crypto.tink.internal.TinkBugException.exceptionIsBug; 20 21 import com.google.crypto.tink.AccessesPartialKey; 22 import com.google.crypto.tink.InsecureSecretKeyAccess; 23 import com.google.crypto.tink.KeyManager; 24 import com.google.crypto.tink.KeyTemplate; 25 import com.google.crypto.tink.Parameters; 26 import com.google.crypto.tink.PrivateKeyManager; 27 import com.google.crypto.tink.PublicKeySign; 28 import com.google.crypto.tink.PublicKeyVerify; 29 import com.google.crypto.tink.config.internal.TinkFipsUtil; 30 import com.google.crypto.tink.internal.KeyManagerRegistry; 31 import com.google.crypto.tink.internal.LegacyKeyManagerImpl; 32 import com.google.crypto.tink.internal.MutableKeyCreationRegistry; 33 import com.google.crypto.tink.internal.MutableParametersRegistry; 34 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 35 import com.google.crypto.tink.internal.PrimitiveConstructor; 36 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 37 import com.google.crypto.tink.signature.internal.EcdsaProtoSerialization; 38 import com.google.crypto.tink.subtle.EcdsaSignJce; 39 import com.google.crypto.tink.subtle.EcdsaVerifyJce; 40 import com.google.crypto.tink.subtle.EllipticCurves; 41 import com.google.crypto.tink.util.SecretBigInteger; 42 import java.security.GeneralSecurityException; 43 import java.security.KeyPair; 44 import java.security.interfaces.ECPrivateKey; 45 import java.security.interfaces.ECPublicKey; 46 import java.util.Collections; 47 import java.util.HashMap; 48 import java.util.Map; 49 import javax.annotation.Nullable; 50 51 /** 52 * This key manager generates new {@code EcdsaPrivateKey} keys and produces new instances of {@code 53 * EcdsaSignJce}. 54 */ 55 public final class EcdsaSignKeyManager { 56 private static final PrimitiveConstructor<EcdsaPrivateKey, PublicKeySign> 57 PUBLIC_KEY_SIGN_PRIMITIVE_CONSTRUCTOR = 58 PrimitiveConstructor.create( 59 EcdsaSignJce::create, EcdsaPrivateKey.class, PublicKeySign.class); 60 61 private static final PrimitiveConstructor<EcdsaPublicKey, PublicKeyVerify> 62 PUBLIC_KEY_VERIFY_PRIMITIVE_CONSTRUCTOR = 63 PrimitiveConstructor.create( 64 EcdsaVerifyJce::create, EcdsaPublicKey.class, PublicKeyVerify.class); 65 66 private static final PrivateKeyManager<PublicKeySign> legacyPrivateKeyManager = 67 LegacyKeyManagerImpl.createPrivateKeyManager( 68 getKeyType(), PublicKeySign.class, com.google.crypto.tink.proto.EcdsaPrivateKey.parser()); 69 70 private static final KeyManager<PublicKeyVerify> legacyPublicKeyManager = 71 LegacyKeyManagerImpl.create( 72 EcdsaVerifyKeyManager.getKeyType(), 73 PublicKeyVerify.class, 74 KeyMaterialType.ASYMMETRIC_PUBLIC, 75 com.google.crypto.tink.proto.EcdsaPublicKey.parser()); 76 getKeyType()77 static String getKeyType() { 78 return "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey"; 79 } 80 81 @AccessesPartialKey createKey( EcdsaParameters parameters, @Nullable Integer idRequirement)82 private static EcdsaPrivateKey createKey( 83 EcdsaParameters parameters, @Nullable Integer idRequirement) throws GeneralSecurityException { 84 KeyPair keyPair = EllipticCurves.generateKeyPair(parameters.getCurveType().toParameterSpec()); 85 ECPublicKey pubKey = (ECPublicKey) keyPair.getPublic(); 86 ECPrivateKey privKey = (ECPrivateKey) keyPair.getPrivate(); 87 88 EcdsaPublicKey publicKey = 89 EcdsaPublicKey.builder() 90 .setParameters(parameters) 91 .setIdRequirement(idRequirement) 92 .setPublicPoint(pubKey.getW()) 93 .build(); 94 95 return EcdsaPrivateKey.builder() 96 .setPublicKey(publicKey) 97 .setPrivateValue( 98 SecretBigInteger.fromBigInteger(privKey.getS(), InsecureSecretKeyAccess.get())) 99 .build(); 100 } 101 102 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 103 private static final MutableKeyCreationRegistry.KeyCreator<EcdsaParameters> KEY_CREATOR = 104 EcdsaSignKeyManager::createKey; 105 namedParameters()106 private static Map<String, Parameters> namedParameters() throws GeneralSecurityException { 107 Map<String, Parameters> result = new HashMap<>(); 108 result.put("ECDSA_P256", PredefinedSignatureParameters.ECDSA_P256); 109 // This key template does not make sense because IEEE P1363 mandates a raw signature. 110 // It is needed to maintain backward compatibility with SignatureKeyTemplates. 111 result.put("ECDSA_P256_IEEE_P1363", PredefinedSignatureParameters.ECDSA_P256_IEEE_P1363); 112 result.put( 113 "ECDSA_P256_RAW", 114 EcdsaParameters.builder() 115 .setHashType(EcdsaParameters.HashType.SHA256) 116 .setCurveType(EcdsaParameters.CurveType.NIST_P256) 117 .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363) 118 .setVariant(EcdsaParameters.Variant.NO_PREFIX) 119 .build()); 120 // This key template is identical to ECDSA_P256_RAW. 121 // It is needed to maintain backward compatibility with SignatureKeyTemplates. 122 result.put( 123 "ECDSA_P256_IEEE_P1363_WITHOUT_PREFIX", 124 PredefinedSignatureParameters.ECDSA_P256_IEEE_P1363_WITHOUT_PREFIX); 125 result.put("ECDSA_P384", PredefinedSignatureParameters.ECDSA_P384); 126 result.put("ECDSA_P384_IEEE_P1363", PredefinedSignatureParameters.ECDSA_P384_IEEE_P1363); 127 result.put( 128 "ECDSA_P384_SHA512", 129 EcdsaParameters.builder() 130 .setHashType(EcdsaParameters.HashType.SHA512) 131 .setCurveType(EcdsaParameters.CurveType.NIST_P384) 132 .setSignatureEncoding(EcdsaParameters.SignatureEncoding.DER) 133 .setVariant(EcdsaParameters.Variant.TINK) 134 .build()); 135 result.put( 136 "ECDSA_P384_SHA384", 137 EcdsaParameters.builder() 138 .setHashType(EcdsaParameters.HashType.SHA384) 139 .setCurveType(EcdsaParameters.CurveType.NIST_P384) 140 .setSignatureEncoding(EcdsaParameters.SignatureEncoding.DER) 141 .setVariant(EcdsaParameters.Variant.TINK) 142 .build()); 143 result.put("ECDSA_P521", PredefinedSignatureParameters.ECDSA_P521); 144 result.put("ECDSA_P521_IEEE_P1363", PredefinedSignatureParameters.ECDSA_P521_IEEE_P1363); 145 return Collections.unmodifiableMap(result); 146 } 147 148 private static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS = 149 TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_REQUIRES_BORINGCRYPTO; 150 151 /** 152 * Registers the {@link EcdsaSignKeyManager} and the {@link EcdsaVerifyKeyManager} with the 153 * registry, so that the the Ecdsa-Keys can be used with Tink. 154 */ registerPair(boolean newKeyAllowed)155 public static void registerPair(boolean newKeyAllowed) throws GeneralSecurityException { 156 if (!FIPS.isCompatible()) { 157 throw new GeneralSecurityException( 158 "Can not use ECDSA in FIPS-mode, as BoringCrypto module is not available."); 159 } 160 EcdsaProtoSerialization.register(); 161 MutableParametersRegistry.globalInstance().putAll(namedParameters()); 162 MutablePrimitiveRegistry.globalInstance() 163 .registerPrimitiveConstructor(PUBLIC_KEY_SIGN_PRIMITIVE_CONSTRUCTOR); 164 MutablePrimitiveRegistry.globalInstance() 165 .registerPrimitiveConstructor(PUBLIC_KEY_VERIFY_PRIMITIVE_CONSTRUCTOR); 166 MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, EcdsaParameters.class); 167 KeyManagerRegistry.globalInstance() 168 .registerKeyManagerWithFipsCompatibility(legacyPrivateKeyManager, FIPS, newKeyAllowed); 169 KeyManagerRegistry.globalInstance() 170 .registerKeyManagerWithFipsCompatibility(legacyPublicKeyManager, FIPS, false); 171 } 172 173 /** 174 * @return A {@link KeyTemplate} that generates new instances of ECDSA keys with the following 175 * parameters: 176 * <ul> 177 * <li>Hash function: SHA256 178 * <li>Curve: NIST P-256 179 * <li>Signature encoding: DER (this is the encoding that Java uses). 180 * <li>Prefix type: {@link KeyTemplate.OutputPrefixType#TINK}. 181 * </ul> 182 */ ecdsaP256Template()183 public static final KeyTemplate ecdsaP256Template() { 184 return exceptionIsBug( 185 () -> 186 KeyTemplate.createFrom( 187 EcdsaParameters.builder() 188 .setSignatureEncoding(EcdsaParameters.SignatureEncoding.DER) 189 .setCurveType(EcdsaParameters.CurveType.NIST_P256) 190 .setHashType(EcdsaParameters.HashType.SHA256) 191 .setVariant(EcdsaParameters.Variant.TINK) 192 .build())); 193 } 194 195 /** 196 * @return A {@link KeyTemplate} that generates new instances of ECDSA keys with the following 197 * parameters: 198 * <ul> 199 * <li>Hash function: SHA256 200 * <li>Curve: NIST P-256 201 * <li>Signature encoding: DER (this is the encoding that Java uses). 202 * <li>Prefix type: RAW (no prefix). 203 * </ul> 204 * Keys generated from this template create raw signatures of exactly 64 bytes. It is 205 * compatible with JWS and most other libraries. 206 */ rawEcdsaP256Template()207 public static final KeyTemplate rawEcdsaP256Template() { 208 return exceptionIsBug( 209 () -> 210 KeyTemplate.createFrom( 211 EcdsaParameters.builder() 212 .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363) 213 .setCurveType(EcdsaParameters.CurveType.NIST_P256) 214 .setHashType(EcdsaParameters.HashType.SHA256) 215 .setVariant(EcdsaParameters.Variant.NO_PREFIX) 216 .build())); 217 } 218 EcdsaSignKeyManager()219 private EcdsaSignKeyManager() {} 220 } 221