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.subtle; 18 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertThrows; 21 import static org.junit.Assert.assertTrue; 22 23 import com.google.crypto.tink.PublicKeySign; 24 import com.google.crypto.tink.PublicKeyVerify; 25 import com.google.crypto.tink.config.TinkFips; 26 import com.google.crypto.tink.config.internal.TinkFipsUtil; 27 import com.google.crypto.tink.signature.EcdsaPrivateKey; 28 import com.google.crypto.tink.signature.EcdsaPublicKey; 29 import com.google.crypto.tink.signature.internal.testing.EcdsaTestUtil; 30 import com.google.crypto.tink.signature.internal.testing.SignatureTestVector; 31 import com.google.crypto.tink.subtle.EllipticCurves.EcdsaEncoding; 32 import com.google.crypto.tink.subtle.Enums.HashType; 33 import com.google.crypto.tink.testing.TestUtil; 34 import java.security.GeneralSecurityException; 35 import java.security.KeyPair; 36 import java.security.KeyPairGenerator; 37 import java.security.Security; 38 import java.security.Signature; 39 import java.security.interfaces.ECPrivateKey; 40 import java.security.interfaces.ECPublicKey; 41 import java.security.spec.ECParameterSpec; 42 import org.conscrypt.Conscrypt; 43 import org.junit.Assume; 44 import org.junit.Before; 45 import org.junit.Test; 46 import org.junit.experimental.theories.DataPoints; 47 import org.junit.experimental.theories.FromDataPoints; 48 import org.junit.experimental.theories.Theories; 49 import org.junit.experimental.theories.Theory; 50 import org.junit.runner.RunWith; 51 52 /** Unit tests for EcdsaSignJce. */ 53 @RunWith(Theories.class) 54 public class EcdsaSignJceTest { 55 56 @Before useConscrypt()57 public void useConscrypt() throws Exception { 58 // If Tink is build in FIPS-only mode, then we register Conscrypt for the tests. 59 if (TinkFips.useOnlyFips()) { 60 try { 61 Conscrypt.checkAvailability(); 62 Security.addProvider(Conscrypt.newProvider()); 63 } catch (Throwable cause) { 64 throw new IllegalStateException( 65 "Cannot test ECDSA sign in FIPS-mode without Conscrypt Provider", cause); 66 } 67 } 68 } 69 70 @Test testBasic()71 public void testBasic() throws Exception { 72 Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable()); 73 74 ECParameterSpec ecParams = EllipticCurves.getNistP256Params(); 75 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); 76 keyGen.initialize(ecParams); 77 KeyPair keyPair = keyGen.generateKeyPair(); 78 ECPublicKey pub = (ECPublicKey) keyPair.getPublic(); 79 ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate(); 80 81 // Sign with EcdsaSign. 82 String message = "Hello"; 83 EcdsaSignJce signer = new EcdsaSignJce(priv, HashType.SHA256, EcdsaEncoding.DER); 84 byte[] signature = signer.sign(message.getBytes("UTF-8")); 85 86 // Verify with JCE's Signature. 87 Signature verifier = Signature.getInstance("SHA256WithECDSA"); 88 verifier.initVerify(pub); 89 verifier.update(message.getBytes("UTF-8")); 90 assertTrue(verifier.verify(signature)); 91 } 92 93 @Test testConstructorExceptions()94 public void testConstructorExceptions() throws Exception { 95 Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable()); 96 97 ECParameterSpec ecParams = EllipticCurves.getNistP256Params(); 98 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); 99 keyGen.initialize(ecParams); 100 KeyPair keyPair = keyGen.generateKeyPair(); 101 ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate(); 102 103 GeneralSecurityException e = 104 assertThrows( 105 GeneralSecurityException.class, 106 () -> new EcdsaSignJce(priv, HashType.SHA1, EcdsaEncoding.DER)); 107 TestUtil.assertExceptionContains(e, "Unsupported hash: SHA1"); 108 } 109 110 @Test testBitFlipAgainstSignatureInstance()111 public void testBitFlipAgainstSignatureInstance() throws Exception { 112 Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable()); 113 114 ECParameterSpec ecParams = EllipticCurves.getNistP256Params(); 115 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); 116 keyGen.initialize(ecParams); 117 KeyPair keyPair = keyGen.generateKeyPair(); 118 ECPublicKey pub = (ECPublicKey) keyPair.getPublic(); 119 ECPrivateKey priv = (ECPrivateKey) keyPair.getPrivate(); 120 121 // Sign with EcdsaSign. 122 String message = "Hello"; 123 EcdsaSignJce signer = new EcdsaSignJce(priv, HashType.SHA256, EcdsaEncoding.DER); 124 byte[] signature = signer.sign(message.getBytes("UTF-8")); 125 126 for (int i = 0; i < signature.length; i++) { 127 for (int j = 0; j < 8; j++) { 128 signature[i] = (byte) (signature[i] ^ (1 << j)); 129 // Verify with JCE's Signature. 130 Signature verifier = Signature.getInstance("SHA256WithECDSA"); 131 verifier.initVerify(pub); 132 verifier.update(message.getBytes("UTF-8")); 133 boolean verified = true; 134 try { 135 verified = verifier.verify(signature); 136 } catch (GeneralSecurityException expected) { 137 verified = false; 138 } 139 assertFalse(verified); 140 signature[i] = (byte) (signature[i] ^ (1 << j)); 141 } 142 } 143 } 144 145 @Test testFailIfFipsModuleNotAvailable()146 public void testFailIfFipsModuleNotAvailable() throws Exception { 147 Assume.assumeTrue(TinkFips.useOnlyFips() && !TinkFipsUtil.fipsModuleAvailable()); 148 149 ECParameterSpec ecParams = EllipticCurves.getNistP256Params(); 150 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); 151 keyGen.initialize(ecParams); 152 KeyPair keyPair = keyGen.generateKeyPair(); 153 154 assertThrows( 155 GeneralSecurityException.class, 156 () -> 157 new EcdsaSignJce( 158 (ECPrivateKey) keyPair.getPrivate(), HashType.SHA256, EcdsaEncoding.DER)); 159 } 160 161 @Theory test_validateSignatureInTestVector( @romDataPoints"allTests") SignatureTestVector testVector)162 public void test_validateSignatureInTestVector( 163 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 164 PublicKeyVerify verifier = 165 EcdsaVerifyJce.create((EcdsaPublicKey) testVector.getPrivateKey().getPublicKey()); 166 verifier.verify(testVector.getSignature(), testVector.getMessage()); 167 } 168 169 @Theory test_computeAndValidateFreshSignatureWithTestVector( @romDataPoints"allTests") SignatureTestVector testVector)170 public void test_computeAndValidateFreshSignatureWithTestVector( 171 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 172 PublicKeySign signer = EcdsaSignJce.create((EcdsaPrivateKey) testVector.getPrivateKey()); 173 byte[] signature = signer.sign(testVector.getMessage()); 174 PublicKeyVerify verifier = 175 EcdsaVerifyJce.create((EcdsaPublicKey) testVector.getPrivateKey().getPublicKey()); 176 verifier.verify(signature, testVector.getMessage()); 177 } 178 179 @Theory test_validateSignatureInTestVectorWithWrongMessage_throws( @romDataPoints"allTests") SignatureTestVector testVector)180 public void test_validateSignatureInTestVectorWithWrongMessage_throws( 181 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 182 PublicKeyVerify verifier = 183 EcdsaVerifyJce.create((EcdsaPublicKey) testVector.getPrivateKey().getPublicKey()); 184 byte[] modifiedMessage = Bytes.concat(testVector.getMessage(), new byte[] {0x01}); 185 assertThrows( 186 GeneralSecurityException.class, 187 () -> verifier.verify(testVector.getSignature(), modifiedMessage)); 188 } 189 190 @DataPoints("allTests") 191 public static final SignatureTestVector[] ALL_TEST_VECTORS = 192 EcdsaTestUtil.createEcdsaTestVectors(); 193 } 194