blob: 6d3d268f44626d846dfb300b6b4fc78510437641 [file] [log] [blame]
// Copyright 2018 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 static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.PublicKeyVerify;
import com.google.crypto.tink.TestUtil;
import com.google.crypto.tink.proto.HashType;
import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
import com.google.crypto.tink.proto.RsaSsaPssKeyFormat;
import com.google.crypto.tink.proto.RsaSsaPssParams;
import com.google.crypto.tink.proto.RsaSsaPssPrivateKey;
import com.google.crypto.tink.proto.RsaSsaPssPublicKey;
import com.google.crypto.tink.subtle.Random;
import com.google.protobuf.ByteString;
import java.security.GeneralSecurityException;
import java.security.spec.RSAKeyGenParameterSpec;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for RsaSsaPssVerifyKeyManager. */
@RunWith(JUnit4.class)
public class RsaSsaPssVerifyKeyManagerTest {
private final RsaSsaPssSignKeyManager signManager = new RsaSsaPssSignKeyManager();
private final RsaSsaPssSignKeyManager.KeyFactory<RsaSsaPssKeyFormat, RsaSsaPssPrivateKey>
factory = signManager.keyFactory();
private final RsaSsaPssVerifyKeyManager verifyManager = new RsaSsaPssVerifyKeyManager();
static class NistTestVector {
byte[] msg;
byte[] sig;
RsaSsaPssPublicKey publicKeyProto;
public NistTestVector(
String modulus,
String exponent,
String msg,
String sig,
HashType sigHash,
HashType mgf1Hash,
int saltLength)
throws Exception {
this.msg = TestUtil.hexDecode(msg);
this.sig = TestUtil.hexDecode(sig);
this.publicKeyProto =
TestUtil.createRsaSsaPssPubKey(
TestUtil.hexDecode(modulus),
TestUtil.hexDecode(exponent),
sigHash,
mgf1Hash,
saltLength);
}
}
// Test vector from
// https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Digital-Signatures
static NistTestVector[] nistTestVectors;
@BeforeClass
public static void setUpNistTestVectors() throws Exception {
nistTestVectors =
new NistTestVector[] {
new NistTestVector(
"a47d04e7cacdba4ea26eca8a4c6e14563c2ce03b623b768c0d49868a57121301dbf783d82f4c055e73960e70550187d0af62ac3496f0a3d9103c2eb7919a72752fa7ce8c688d81e3aee99468887a15288afbb7acb845b7c522b5c64e678fcd3d22feb84b44272700be527d2b2025a3f83c2383bf6a39cf5b4e48b3cf2f56eef0dfff18555e31037b915248694876f3047814415164f2c660881e694b58c28038a032ad25634aad7b39171dee368e3d59bfb7299e4601d4587e68caaf8db457b75af42fc0cf1ae7caced286d77fac6cedb03ad94f1433d2c94d08e60bc1fdef0543cd2951e765b38230fdd18de5d2ca627ddc032fe05bbd2ff21e2db1c2f94d8b",
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e43f",
"e002377affb04f0fe4598de9d92d31d6c786040d5776976556a2cfc55e54a1dcb3cb1b126bd6a4bed2a184990ccea773fcc79d246553e6c64f686d21ad4152673cafec22aeb40f6a084e8a5b4991f4c64cf8a927effd0fd775e71e8329e41fdd4457b3911173187b4f09a817d79ea2397fc12dfe3d9c9a0290c8ead31b6690a6",
"4f9b425c2058460e4ab2f5c96384da2327fd29150f01955a76b4efe956af06dc08779a374ee4607eab61a93adc5608f4ec36e47f2a0f754e8ff839a8a19b1db1e884ea4cf348cd455069eb87afd53645b44e28a0a56808f5031da5ba9112768dfbfca44ebe63a0c0572b731d66122fb71609be1480faa4e4f75e43955159d70f081e2a32fbb19a48b9f162cf6b2fb445d2d6994bc58910a26b5943477803cdaaa1bd74b0da0a5d053d8b1dc593091db5388383c26079f344e2aea600d0e324164b450f7b9b465111b7265f3b1b063089ae7e2623fc0fda8052cf4bf3379102fbf71d7c98e8258664ceed637d20f95ff0111881e650ce61f251d9c3a629ef222d",
HashType.SHA256,
HashType.SHA256,
32),
new NistTestVector(
"99a5c8d094a5f917034667a0408b7ecfcaacc3f9784444e21773c3461ec355f0d0f52a5db0568a71d388696788ef66ae7340c6b28dbf925fe83557986575f79cca69217221397ed5808a26f7e7e714c93235f914d45c4a9af4619b20f511ad644bd3412dfdf0ff717f7aac746f310bfa9a141ac3dbf01c1fc74febd197938419c262293505c35f402f9053ad13c51a5960ecde55ec829e953f941af733e58705913767e7a7200d1d09e7e7e2d269fa29a558bb16304b059f13f4ca560a8101fe3720b4a779ec126427326caa132a3d3611d7dbc50336fac789ec406b397e1e36d7daf9b624bf639c82b859288747690c730c980b2f5a239dd95ad5389a2ec90c5778604713710383ae55d4d28c06d4ac26f0d1231f1d6762c8e0d918118156bc637760daea184746b8dcf6f61db274a7ddceaa074937ababad4549b97ab992494a807208abd789823f5d75c4b994089c8072cfc254e0d8202fd896476e96ad9d309a0e8e7301282f07eb2ae8edefb7dbbe13b96e8b4024c6b84de0a05e150285",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008a649",
"cc21593a6a0f737e2970b7c07984b070d761726296a07e24e056e68ff846b29cc1548179843d74dcee86479858b2c16e4cb84f2544b4ecdcb4dd43a04bb7183a768ae44a2712bf9ad47883acc2812f958306890ebea408c92eb4f001ed7dbf55f3a9c8d6d9f61e5fe32eb3253e59c18e863169478cd69b9155c335db66016f96",
"0aa572a6845b870b8909a683bb7e6e7616f77beff28746116d8bc4b7335546b51e8006ed0fc9a0d66f63ce0b9ebf792d7efd4305d7624d545400a5fd6a06b78f174b86803f7cd1cc93e3a97286f0ea590e40ff26195aa219fe1510a016785223606d9311a16c59a8fe4a6da6ecd0c1d7775039290c2aaa17ed1eb1b54374f7e572db13cca3a638575f8004aa54a2fa98422fc07e43ad3a20dd93001493442677d883914dc74ec1cbebbbd3d2b6bad4666d91457b69b46a1a61f21298f1a67942ec86c876322dd366ed167814e9c8fc9040c5b4b7a859bbd880cb6bc241b9e327ce779e0783b1cf445e0b2f5771b3f5822a1364391c154dc506fff1fb9d9a35f80199a6b30b4b92b92619a40e21aea19284015863c44866c61ed904a7ad19ee04d966c0aae390636243565581ff20bd6e3cfb6e31f5afba964b311dc2d023a21998c8dd50ca453699190bd467429e2f88ace29c4d1da4da61aac1eda2380230aa8dbb63c75a3c1ec04da3a1f880c9c747acdb74a8395af58f5f044015ccaf6e94",
HashType.SHA512,
HashType.SHA512,
0),
};
}
@Test
public void basics() throws Exception {
assertThat(verifyManager.getKeyType())
.isEqualTo("type.googleapis.com/google.crypto.tink.RsaSsaPssPublicKey");
assertThat(verifyManager.getVersion()).isEqualTo(0);
assertThat(verifyManager.keyMaterialType()).isEqualTo(KeyMaterialType.ASYMMETRIC_PUBLIC);
}
@Test
public void validateKey_empty_throws() throws Exception {
try {
verifyManager.validateKey(RsaSsaPssPublicKey.getDefaultInstance());
fail();
} catch (GeneralSecurityException e) {
// expected
}
}
@Test
public void validateKey_generated() throws Exception {
if (TestUtil.isTsan()) {
// factory.createKey is too slow in Tsan.
return;
}
RsaSsaPssKeyFormat keyFormat =
RsaSsaPssKeyFormat.newBuilder()
.setParams(
RsaSsaPssParams.newBuilder()
.setSigHash(HashType.SHA256)
.setMgf1Hash(HashType.SHA256)
.setSaltLength(32))
.setModulusSizeInBits(3072)
.setPublicExponent(ByteString.copyFrom(RSAKeyGenParameterSpec.F4.toByteArray()))
.build();
RsaSsaPssPrivateKey privateKey = factory.createKey(keyFormat);
RsaSsaPssPublicKey publicKey = signManager.getPublicKey(privateKey);
verifyManager.validateKey(publicKey);
}
@Test
public void validateKey_testVector() throws Exception {
if (TestUtil.isTsan()) {
// factory.createKey is too slow in Tsan.
return;
}
RsaSsaPssPublicKey publicKey = nistTestVectors[0].publicKeyProto;
verifyManager.validateKey(publicKey);
}
@Test
public void validateKey_wrongVersion() throws Exception {
RsaSsaPssPublicKey publicKey = nistTestVectors[0].publicKeyProto;
RsaSsaPssPublicKey invalidKey = RsaSsaPssPublicKey.newBuilder(publicKey).setVersion(1).build();
try {
verifyManager.validateKey(invalidKey);
fail();
} catch (GeneralSecurityException e) {
// expected
}
}
@Test
public void validateKey_smallModulus() throws Exception {
RsaSsaPssPublicKey publicKey = nistTestVectors[0].publicKeyProto;
RsaSsaPssPublicKey invalidKey =
RsaSsaPssPublicKey.newBuilder(publicKey)
.setN(ByteString.copyFrom(TestUtil.hexDecode("23")))
.setE(ByteString.copyFrom(TestUtil.hexDecode("03")))
.build();
try {
verifyManager.validateKey(invalidKey);
fail();
} catch (GeneralSecurityException e) {
// expected
}
}
@Test
public void createPrimitive() throws Exception {
if (TestUtil.isTsan()) {
// factory.createKey is too slow in Tsan.
return;
}
RsaSsaPssKeyFormat keyFormat =
RsaSsaPssKeyFormat.newBuilder()
.setParams(
RsaSsaPssParams.newBuilder()
.setSigHash(HashType.SHA256)
.setMgf1Hash(HashType.SHA256)
.setSaltLength(32))
.setModulusSizeInBits(3072)
.setPublicExponent(ByteString.copyFrom(RSAKeyGenParameterSpec.F4.toByteArray()))
.build();
RsaSsaPssPrivateKey privateKey = factory.createKey(keyFormat);
RsaSsaPssPublicKey publicKey = signManager.getPublicKey(privateKey);
PublicKeySign signer = signManager.getPrimitive(privateKey, PublicKeySign.class);
PublicKeyVerify verifier = verifyManager.getPrimitive(publicKey, PublicKeyVerify.class);
byte[] message = Random.randBytes(135);
verifier.verify(signer.sign(message), message);
}
@Test
public void createPrimitive_anotherKey_throws() throws Exception {
if (TestUtil.isTsan()) {
// factory.createKey is too slow in Tsan.
return;
}
RsaSsaPssKeyFormat keyFormat =
RsaSsaPssKeyFormat.newBuilder()
.setParams(
RsaSsaPssParams.newBuilder()
.setSigHash(HashType.SHA256)
.setMgf1Hash(HashType.SHA256)
.setSaltLength(32))
.setModulusSizeInBits(3072)
.setPublicExponent(ByteString.copyFrom(RSAKeyGenParameterSpec.F4.toByteArray()))
.build();
RsaSsaPssPrivateKey privateKey = factory.createKey(keyFormat);
// Create a different key.
RsaSsaPssPublicKey publicKey = signManager.getPublicKey(factory.createKey(keyFormat));
PublicKeySign signer = signManager.getPrimitive(privateKey, PublicKeySign.class);
PublicKeyVerify verifier = verifyManager.getPrimitive(publicKey, PublicKeyVerify.class);
byte[] message = Random.randBytes(135);
byte[] signature = signer.sign(message);
try {
verifier.verify(signature, message);
fail();
} catch (GeneralSecurityException e) {
// expected
}
}
@Test
public void testNistTestVector() throws Exception {
for (NistTestVector t : nistTestVectors) {
PublicKeyVerify verifier =
verifyManager.getPrimitive(t.publicKeyProto, PublicKeyVerify.class);
try {
verifier.verify(t.sig, t.msg);
} catch (GeneralSecurityException e) {
fail("Valid signature, should not throw exception" + e);
}
}
}
}