From 7daeb33e39e8c69fd12efd8fc9a3af470e1af0f5 Mon Sep 17 00:00:00 2001 From: thaidn <thaidn@google.com> Date: Wed, 20 Feb 2019 14:29:56 -0800 Subject: [PATCH] Add a utility that can read keys in PEM format. NOKEYCHECK=True PiperOrigin-RevId: 234869572 GitOrigin-RevId: 6ca4bf591b4ea1ae7e06ca0e0dfccde57b8906a1 --- cc/subtle/common_enums.cc | 2 + cc/subtle/common_enums.h | 1 + cc/subtle/common_enums_test.cc | 1 + cc/util/enums.cc | 7 + cc/util/enums_test.cc | 9 +- .../google/crypto/tink/signature/SigUtil.java | 19 +- .../com/google/crypto/tink/subtle/BUILD.bazel | 1 + .../crypto/tink/subtle/EllipticCurves.java | 10 +- .../com/google/crypto/tink/subtle/Enums.java | 1 + .../google/crypto/tink/subtle/PemKeyType.java | 151 ++++++++++++++ .../google/crypto/tink/subtle/SubtleUtil.java | 2 + .../google/crypto/tink/subtle/Validators.java | 7 +- .../crypto/tink/signature/SigUtilTest.java | 2 +- .../crypto/tink/subtle/EcdsaSignJceTest.java | 2 +- .../tink/subtle/EcdsaVerifyJceTest.java | 2 +- .../crypto/tink/subtle/PemKeyTypeTest.java | 191 ++++++++++++++++++ .../tink/subtle/RsaSsaPkcs1SignJceTest.java | 2 +- .../tink/subtle/RsaSsaPkcs1VerifyJceTest.java | 2 +- .../tink/subtle/RsaSsaPssSignJceTest.java | 2 +- .../tink/subtle/RsaSsaPssVerifyJceTest.java | 2 +- .../crypto/tink/subtle/ValidatorsTest.java | 2 +- proto/common.proto | 1 + 22 files changed, 393 insertions(+), 26 deletions(-) create mode 100644 java/src/main/java/com/google/crypto/tink/subtle/PemKeyType.java create mode 100644 java/src/test/java/com/google/crypto/tink/subtle/PemKeyTypeTest.java diff --git a/cc/subtle/common_enums.cc b/cc/subtle/common_enums.cc index 62d4c3096..8f4ea62b0 100644 --- a/cc/subtle/common_enums.cc +++ b/cc/subtle/common_enums.cc @@ -58,6 +58,8 @@ std::string EnumToString(HashType type) { return "SHA1"; case HashType::SHA256: return "SHA256"; + case HashType::SHA384: + return "SHA384"; case HashType::SHA512: return "SHA512"; case HashType::UNKNOWN_HASH: diff --git a/cc/subtle/common_enums.h b/cc/subtle/common_enums.h index a1d1277ea..aac78b658 100644 --- a/cc/subtle/common_enums.h +++ b/cc/subtle/common_enums.h @@ -43,6 +43,7 @@ enum EcPointFormat { enum HashType { UNKNOWN_HASH = 0, SHA1 = 1, // SHA1 for digital signature is deprecated but HMAC-SHA1 is fine. + SHA384 = 2, SHA256 = 3, SHA512 = 4, }; diff --git a/cc/subtle/common_enums_test.cc b/cc/subtle/common_enums_test.cc index e52757e0d..ce355028e 100644 --- a/cc/subtle/common_enums_test.cc +++ b/cc/subtle/common_enums_test.cc @@ -35,6 +35,7 @@ TEST_F(CommonEnumsTest, testEllipticCurveTypeToString) { TEST_F(CommonEnumsTest, testHashTypeToString) { EXPECT_EQ("SHA1", EnumToString(HashType::SHA1)); EXPECT_EQ("SHA256", EnumToString(HashType::SHA256)); + EXPECT_EQ("SHA384", EnumToString(HashType::SHA384)); EXPECT_EQ("SHA512", EnumToString(HashType::SHA512)); EXPECT_EQ("UNKNOWN_HASH", EnumToString(HashType::UNKNOWN_HASH)); EXPECT_EQ("UNKNOWN_HASH: 42", EnumToString((HashType)42)); diff --git a/cc/util/enums.cc b/cc/util/enums.cc index 6ea7e9da8..e39a8360f 100644 --- a/cc/util/enums.cc +++ b/cc/util/enums.cc @@ -88,6 +88,8 @@ pb::HashType Enums::SubtleToProto(subtle::HashType type) { return pb::HashType::SHA1; case subtle::HashType::SHA256: return pb::HashType::SHA256; + case subtle::HashType::SHA384: + return pb::HashType::SHA384; case subtle::HashType::SHA512: return pb::HashType::SHA512; default: @@ -102,6 +104,8 @@ subtle::HashType Enums::ProtoToSubtle(pb::HashType type) { return subtle::HashType::SHA1; case pb::HashType::SHA256: return subtle::HashType::SHA256; + case pb::HashType::SHA384: + return subtle::HashType::SHA384; case pb::HashType::SHA512: return subtle::HashType::SHA512; default: @@ -156,6 +160,8 @@ const char* Enums::HashName(pb::HashType hash_type) { return "SHA1"; case pb::HashType::SHA256: return "SHA256"; + case pb::HashType::SHA384: + return "SHA384"; case pb::HashType::SHA512: return "SHA512"; default: @@ -208,6 +214,7 @@ pb::KeyStatusType Enums::KeyStatus(absl::string_view name) { pb::HashType Enums::Hash(absl::string_view name) { if (name == "SHA1") return pb::HashType::SHA1; if (name == "SHA256") return pb::HashType::SHA256; + if (name == "SHA384") return pb::HashType::SHA384; if (name == "SHA512") return pb::HashType::SHA512; return pb::HashType::UNKNOWN_HASH; } diff --git a/cc/util/enums_test.cc b/cc/util/enums_test.cc index 5f4f55291..8af8126b9 100644 --- a/cc/util/enums_test.cc +++ b/cc/util/enums_test.cc @@ -73,6 +73,8 @@ TEST_F(EnumsTest, testHashType) { Enums::SubtleToProto(subtle::HashType::SHA1)); EXPECT_EQ(pb::HashType::SHA256, Enums::SubtleToProto(subtle::HashType::SHA256)); + EXPECT_EQ(pb::HashType::SHA384, + Enums::SubtleToProto(subtle::HashType::SHA384)); EXPECT_EQ(pb::HashType::SHA512, Enums::SubtleToProto(subtle::HashType::SHA512)); EXPECT_EQ(pb::HashType::UNKNOWN_HASH, @@ -84,6 +86,8 @@ TEST_F(EnumsTest, testHashType) { Enums::ProtoToSubtle(pb::HashType::SHA1)); EXPECT_EQ(subtle::HashType::SHA256, Enums::ProtoToSubtle(pb::HashType::SHA256)); + EXPECT_EQ(subtle::HashType::SHA384, + Enums::ProtoToSubtle(pb::HashType::SHA384)); EXPECT_EQ(subtle::HashType::SHA512, Enums::ProtoToSubtle(pb::HashType::SHA512)); EXPECT_EQ(subtle::HashType::UNKNOWN_HASH, @@ -102,7 +106,7 @@ TEST_F(EnumsTest, testHashType) { count++; } } - EXPECT_EQ(4, count); + EXPECT_EQ(5, count); } TEST_F(EnumsTest, testEcPointFormat) { @@ -218,6 +222,7 @@ TEST_F(EnumsTest, testHashName) { EXPECT_EQ(pb::HashType::SHA1, Enums::Hash("SHA1")); EXPECT_EQ(pb::HashType::SHA256, Enums::Hash("SHA256")); + EXPECT_EQ(pb::HashType::SHA384, Enums::Hash("SHA384")); EXPECT_EQ(pb::HashType::SHA512, Enums::Hash("SHA512")); EXPECT_EQ(pb::HashType::UNKNOWN_HASH, Enums::Hash("Other string")); EXPECT_EQ(pb::HashType::UNKNOWN_HASH, Enums::Hash("UNKNOWN_HASH")); @@ -232,7 +237,7 @@ TEST_F(EnumsTest, testHashName) { count++; } } - EXPECT_EQ(4, count); + EXPECT_EQ(5, count); } TEST_F(EnumsTest, testKeyMaterialName) { diff --git a/java/src/main/java/com/google/crypto/tink/signature/SigUtil.java b/java/src/main/java/com/google/crypto/tink/signature/SigUtil.java index 1223bb794..3500417d2 100644 --- a/java/src/main/java/com/google/crypto/tink/signature/SigUtil.java +++ b/java/src/main/java/com/google/crypto/tink/signature/SigUtil.java @@ -24,7 +24,6 @@ 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 com.google.crypto.tink.subtle.Validators; import java.security.GeneralSecurityException; final class SigUtil { @@ -50,14 +49,17 @@ final class SigUtil { 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's + // 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: - /* fall through */ + 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); @@ -77,7 +79,7 @@ final class SigUtil { */ public static void validateRsaSsaPkcs1Params(RsaSsaPkcs1Params params) throws GeneralSecurityException { - Validators.validateSignatureHash(toHashType(params.getHashType())); + toHashType(params.getHashType()); } /** @@ -102,7 +104,7 @@ final class SigUtil { */ public static void validateRsaSsaPssParams(RsaSsaPssParams params) throws GeneralSecurityException { - Validators.validateSignatureHash(toHashType(params.getSigHash())); + toHashType(params.getSigHash()); if (params.getSigHash() != params.getMgf1Hash()) { throw new GeneralSecurityException("MGF1 hash is different from signature hash"); } @@ -111,15 +113,16 @@ final class SigUtil { /** Converts protobuf enum {@code HashType} to raw Java enum {@code Enums.HashType}. */ public static Enums.HashType toHashType(HashType hash) throws GeneralSecurityException { switch (hash) { - case SHA1: - return Enums.HashType.SHA1; case SHA256: return Enums.HashType.SHA256; + case SHA384: + return Enums.HashType.SHA384; case SHA512: return Enums.HashType.SHA512; default: - throw new GeneralSecurityException("unknown hash type: " + hash); + break; } + throw new GeneralSecurityException("unsupported hash type: " + hash.name()); } /** Converts protobuf enum {@code EllipticCurveType} to raw Java enum {code CurveType}. */ diff --git a/java/src/main/java/com/google/crypto/tink/subtle/BUILD.bazel b/java/src/main/java/com/google/crypto/tink/subtle/BUILD.bazel index 90a76e00c..57b916a12 100644 --- a/java/src/main/java/com/google/crypto/tink/subtle/BUILD.bazel +++ b/java/src/main/java/com/google/crypto/tink/subtle/BUILD.bazel @@ -26,6 +26,7 @@ java_library( "Enums.java", "Hex.java", "ImmutableByteArray.java", + "PemKeyType.java", "Random.java", "SubtleUtil.java", "Validators.java", diff --git a/java/src/main/java/com/google/crypto/tink/subtle/EllipticCurves.java b/java/src/main/java/com/google/crypto/tink/subtle/EllipticCurves.java index 52b17ca72..0980deec8 100644 --- a/java/src/main/java/com/google/crypto/tink/subtle/EllipticCurves.java +++ b/java/src/main/java/com/google/crypto/tink/subtle/EllipticCurves.java @@ -132,10 +132,10 @@ public final class EllipticCurves { throw new GeneralSecurityException("point is at infinity"); } // Check 0 <= x < p and 0 <= y < p. - if (x.signum() == -1 || x.compareTo(p) != -1) { + if (x.signum() == -1 || x.compareTo(p) >= 0) { throw new GeneralSecurityException("x is out of range"); } - if (y.signum() == -1 || y.compareTo(p) != -1) { + if (y.signum() == -1 || y.compareTo(p) >= 0) { throw new GeneralSecurityException("y is out of range"); } // Check y^2 == x^3 + a x + b (mod p) @@ -216,7 +216,7 @@ public final class EllipticCurves { * @param curve must be a prime order elliptic curve * @return the size of an element in bits */ - private static int fieldSizeInBits(EllipticCurve curve) throws GeneralSecurityException { + static int fieldSizeInBits(EllipticCurve curve) throws GeneralSecurityException { return getModulus(curve).subtract(BigInteger.ONE).bitLength(); } @@ -717,7 +717,7 @@ public final class EllipticCurves { throw new GeneralSecurityException("invalid format"); } BigInteger x = new BigInteger(1, Arrays.copyOfRange(encoded, 1, encoded.length)); - if (x.signum() == -1 || x.compareTo(p) != -1) { + if (x.signum() == -1 || x.compareTo(p) >= 0) { throw new GeneralSecurityException("x is out of range"); } BigInteger y = getY(x, lsb, curve); @@ -911,7 +911,7 @@ public final class EllipticCurves { throws GeneralSecurityException { EllipticCurve privateKeyCurve = privateKey.getParams().getCurve(); BigInteger x = new BigInteger(1, secret); - if (x.signum() == -1 || x.compareTo(getModulus(privateKeyCurve)) != -1) { + if (x.signum() == -1 || x.compareTo(getModulus(privateKeyCurve)) >= 0) { throw new GeneralSecurityException("shared secret is out of range"); } // This will throw if x is not a valid coordinate. diff --git a/java/src/main/java/com/google/crypto/tink/subtle/Enums.java b/java/src/main/java/com/google/crypto/tink/subtle/Enums.java index 803b519f5..e66db606b 100644 --- a/java/src/main/java/com/google/crypto/tink/subtle/Enums.java +++ b/java/src/main/java/com/google/crypto/tink/subtle/Enums.java @@ -22,6 +22,7 @@ public final class Enums { public enum HashType { SHA1, // Using SHA1 for digital signature is deprecated but HMAC-SHA1 is fine. SHA256, + SHA384, SHA512, }; } diff --git a/java/src/main/java/com/google/crypto/tink/subtle/PemKeyType.java b/java/src/main/java/com/google/crypto/tink/subtle/PemKeyType.java new file mode 100644 index 000000000..e5ae2b7ce --- /dev/null +++ b/java/src/main/java/com/google/crypto/tink/subtle/PemKeyType.java @@ -0,0 +1,151 @@ +// 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.subtle; + +import com.google.crypto.tink.subtle.Enums.HashType; +import java.io.BufferedReader; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.interfaces.ECKey; +import java.security.interfaces.RSAKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** PEM key types that Tink supports */ +public enum PemKeyType { + // RSASSA-PSS 2048 bit key with a SHA256 digest. + RSA_PSS_2048_SHA256("RSA", "RSASSA-PSS", 2048, HashType.SHA256), + // RSASSA-PSS 3072 bit key with a SHA256 digest. + RSA_PSS_3072_SHA256("RSA", "RSASSA-PSS", 3072, HashType.SHA256), + // RSASSA-PSS 4096 bit key with a SHA256 digest. + RSA_PSS_4096_SHA256("RSA", "RSASSA-PSS", 4096, HashType.SHA256), + // RSASSA-PSS 4096 bit key with a SHA512 digest. + RSA_PSS_4096_SHA512("RSA", "RSASSA-PSS", 4096, HashType.SHA512), + + // RSASSA-PKCS1-v1_5 with a 2048 bit key and a SHA256 digest. + RSA_SIGN_PKCS1_2048_SHA256("RSA", "RSASSA-PKCS1-v1_5", 2048, HashType.SHA256), + // RSASSA-PKCS1-v1_5 with a 3072 bit key and a SHA256 digest. + RSA_SIGN_PKCS1_3072_SHA256("RSA", "RSASSA-PKCS1-v1_5", 3072, HashType.SHA256), + // RSASSA-PKCS1-v1_5 with a 4096 bit key and a SHA256 digest. + RSA_SIGN_PKCS1_4096_SHA256("RSA", "RSASSA-PKCS1-v1_5", 4096, HashType.SHA256), + // RSASSA-PKCS1-v1_5 with a 4096 bit key and a SHA512 digest. + RSA_SIGN_PKCS1_4096_SHA512("RSA", "RSASSA-PKCS1-v1_5", 4096, HashType.SHA512), + + // ECDSA on the NIST P-256 curve with a SHA256 digest. + ECDSA_P256_SHA256("EC", "ECDSA", 256, HashType.SHA256), + // ECDSA on the NIST P-384 curve with a SHA384 digest. + ECDSA_P384_SHA384("EC", "ECDSA", 384, HashType.SHA384), + // ECDSA on the NIST P-521 curve with a SHA512 digest. + ECDSA_P521_SHA512("EC", "ECDSA", 521, HashType.SHA512); + + public final String keyType; + public final String algorithm; + public final int keySizeInBits; + public final HashType hash; + + PemKeyType(String keyType, String algorithm, int keySizeInBits, HashType hash) { + this.keyType = keyType; + this.algorithm = algorithm; + this.keySizeInBits = keySizeInBits; + this.hash = hash; + } + + private static final String PUBLIC_KEY = "PUBLIC KEY"; + private static final String PRIVATE_KEY = "PRIVATE KEY"; + private static final String BEGIN = "-----BEGIN "; + private static final String END = "-----END "; + private static final String MARKER = "-----"; + + /** + * Reads a single key from {@code reader}. + * + * @return a {@link Key} or null if the reader doesn't contain a valid PEM. + */ + public Key readKey(BufferedReader reader) throws IOException { + String line = reader.readLine(); + while (line != null && !line.startsWith(BEGIN)) { + line = reader.readLine(); + } + if (line == null) { + return null; + } + + line = line.trim().substring(BEGIN.length()); + int index = line.indexOf(MARKER); + if (index < 0) { + return null; + } + String type = line.substring(0, index); + String endMarker = END + type + MARKER; + StringBuilder base64key = new StringBuilder(); + + while ((line = reader.readLine()) != null) { + if (line.indexOf(":") > 0) { + // header, ignore + continue; + } + if (line.contains(endMarker)) { + break; + } + base64key.append(line); + } + try { + byte[] key = Base64.decode(base64key.toString(), Base64.DEFAULT); + if (type.contains(PUBLIC_KEY)) { + return getPublicKey(key); + } else if (type.contains(PRIVATE_KEY)) { + return getPrivateKey(key); + } + } catch (GeneralSecurityException | IllegalArgumentException ex) { + return null; + } + return null; + } + + private Key getPublicKey(final byte[] key) throws GeneralSecurityException { + KeyFactory keyFactory = EngineFactory.KEY_FACTORY.getInstance(this.keyType); + return validate(keyFactory.generatePublic(new X509EncodedKeySpec(key))); + } + + private Key getPrivateKey(final byte[] key) throws GeneralSecurityException { + KeyFactory keyFactory = EngineFactory.KEY_FACTORY.getInstance(this.keyType); + return validate(keyFactory.generatePrivate(new PKCS8EncodedKeySpec(key))); + } + + private Key validate(Key key) throws GeneralSecurityException { + if (this.keyType.equals("RSA")) { + RSAKey rsaKey = (RSAKey) key; + int foundKeySizeInBits = rsaKey.getModulus().bitLength(); + if (foundKeySizeInBits != this.keySizeInBits) { + throw new GeneralSecurityException( + String.format( + "invalid RSA key size, want %d got %d", this.keySizeInBits, foundKeySizeInBits)); + } + } else { + ECKey ecKey = (ECKey) key; + int foundKeySizeInBits = EllipticCurves.fieldSizeInBits(ecKey.getParams().getCurve()); + if (foundKeySizeInBits != this.keySizeInBits) { + throw new GeneralSecurityException( + String.format( + "invalid EC key size, want %d got %d", this.keySizeInBits, foundKeySizeInBits)); + } + } + return key; + } +} diff --git a/java/src/main/java/com/google/crypto/tink/subtle/SubtleUtil.java b/java/src/main/java/com/google/crypto/tink/subtle/SubtleUtil.java index a56b6ac3a..fa9862656 100644 --- a/java/src/main/java/com/google/crypto/tink/subtle/SubtleUtil.java +++ b/java/src/main/java/com/google/crypto/tink/subtle/SubtleUtil.java @@ -65,6 +65,8 @@ public class SubtleUtil { return "SHA-1"; case SHA256: return "SHA-256"; + case SHA384: + return "SHA-384"; case SHA512: return "SHA-512"; } diff --git a/java/src/main/java/com/google/crypto/tink/subtle/Validators.java b/java/src/main/java/com/google/crypto/tink/subtle/Validators.java index b5bb2b8a9..1c0adf0e5 100644 --- a/java/src/main/java/com/google/crypto/tink/subtle/Validators.java +++ b/java/src/main/java/com/google/crypto/tink/subtle/Validators.java @@ -80,12 +80,13 @@ public final class Validators { public static void validateSignatureHash(HashType hash) throws GeneralSecurityException { switch (hash) { case SHA256: // fall through + case SHA384: // fall through case SHA512: return; - case SHA1: - throw new GeneralSecurityException("SHA1 is not safe for signature"); + default: + break; } - throw new GeneralSecurityException("Unsupported hash " + hash); + throw new GeneralSecurityException("Unsupported hash: " + hash.name()); } /** diff --git a/java/src/test/java/com/google/crypto/tink/signature/SigUtilTest.java b/java/src/test/java/com/google/crypto/tink/signature/SigUtilTest.java index 58291f292..61f3f2cf5 100644 --- a/java/src/test/java/com/google/crypto/tink/signature/SigUtilTest.java +++ b/java/src/test/java/com/google/crypto/tink/signature/SigUtilTest.java @@ -31,8 +31,8 @@ import org.junit.runners.JUnit4; public final class SigUtilTest { @Test public void testToHashType() throws Exception { - assertEquals(Enums.HashType.SHA1, SigUtil.toHashType(HashType.SHA1)); assertEquals(Enums.HashType.SHA256, SigUtil.toHashType(HashType.SHA256)); + assertEquals(Enums.HashType.SHA384, SigUtil.toHashType(HashType.SHA384)); assertEquals(Enums.HashType.SHA512, SigUtil.toHashType(HashType.SHA512)); try { SigUtil.toHashType(HashType.UNKNOWN_HASH); diff --git a/java/src/test/java/com/google/crypto/tink/subtle/EcdsaSignJceTest.java b/java/src/test/java/com/google/crypto/tink/subtle/EcdsaSignJceTest.java index d7089f385..215b6f640 100644 --- a/java/src/test/java/com/google/crypto/tink/subtle/EcdsaSignJceTest.java +++ b/java/src/test/java/com/google/crypto/tink/subtle/EcdsaSignJceTest.java @@ -75,7 +75,7 @@ public class EcdsaSignJceTest { fail("Unsafe hash, should have thrown exception."); } catch (GeneralSecurityException e) { // Expected. - TestUtil.assertExceptionContains(e, "SHA1 is not safe"); + TestUtil.assertExceptionContains(e, "Unsupported hash: SHA1"); } } diff --git a/java/src/test/java/com/google/crypto/tink/subtle/EcdsaVerifyJceTest.java b/java/src/test/java/com/google/crypto/tink/subtle/EcdsaVerifyJceTest.java index 87d781e52..007e5ed26 100644 --- a/java/src/test/java/com/google/crypto/tink/subtle/EcdsaVerifyJceTest.java +++ b/java/src/test/java/com/google/crypto/tink/subtle/EcdsaVerifyJceTest.java @@ -137,7 +137,7 @@ public class EcdsaVerifyJceTest { fail("Unsafe hash, should have thrown exception."); } catch (GeneralSecurityException e) { // Expected. - TestUtil.assertExceptionContains(e, "SHA1 is not safe"); + TestUtil.assertExceptionContains(e, "Unsupported hash: SHA1"); } } diff --git a/java/src/test/java/com/google/crypto/tink/subtle/PemKeyTypeTest.java b/java/src/test/java/com/google/crypto/tink/subtle/PemKeyTypeTest.java new file mode 100644 index 000000000..0290146b7 --- /dev/null +++ b/java/src/test/java/com/google/crypto/tink/subtle/PemKeyTypeTest.java @@ -0,0 +1,191 @@ +// 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.subtle; + +import static com.google.common.truth.Truth.assertThat; + +import java.io.BufferedReader; +import java.io.StringReader; +import java.security.Key; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for PemKeyType */ +@RunWith(JUnit4.class) +public final class PemKeyTypeTest { + @Before + public void setUp() {} + + @Test + public void readKey_RsaPublicKey_shouldWork() throws Exception { + String pem = + "-----BEGIN PUBLIC KEY-----\n" + + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv90Xf/NN1lRGBofJQzJf\n" + + "lHvo6GAf25GGQGaMmD9T1ZP71CCbJ69lGIS/6akFBg6ECEHGM2EZ4WFLCdr5byUq\n" + + "GCf4mY4WuOn+AcwzwAoDz9ASIFcQOoPclO7JYdfo2SOaumumdb5S/7FkKJ70TGYW\n" + + "j9aTOYWsCcaojbjGDY/JEXz3BSRIngcgOvXBmV1JokcJ/LsrJD263WE9iUknZDhB\n" + + "K7y4ChjHNqL8yJcw/D8xLNiJtIyuxiZ00p/lOVUInr8C/a2C1UGCgEGuXZAEGAdO\n" + + "NVez52n5TLvQP3hRd4MTi7YvfhezRcA4aXyIDOv+TYi4p+OVTYQ+FMbkgoWBm5bq\n" + + "wQIDAQAB\n" + + "-----END PUBLIC KEY-----\n"; + BufferedReader reader = new BufferedReader(new StringReader(pem)); + Key key = PemKeyType.RSA_PSS_2048_SHA256.readKey(reader); + assertThat(key).isNotNull(); + assertThat(key).isInstanceOf(RSAPublicKey.class); + RSAPublicKey rsa = (RSAPublicKey) key; + assertThat(rsa.getModulus()).isNotNull(); + assertThat(rsa.getPublicExponent()).isNotNull(); + } + + @Test + public void readKey_RsaPrivateKey_shouldWork() throws Exception { + String pem = + "-----BEGIN PRIVATE KEY-----\n" + + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8Bn6pA4wksGPK\n" + + "xhRrJnk0mcyKk5hSCFlrlwCs1OUaWAQTMWzFrMW0mdR4FCG6mw2K91rla2F51af8\n" + + "IJjy/E02ampBZrFfIlTbHLPOXdSrgL2L1a213zS2AsMZ1NAEKZwG5eJDf9Ym4oTC\n" + + "nut50YILgwtwYHLvov0ciJjR6q85+59UznZx6itVEqQpDT7Fi7QWOaGb5mMLHCcF\n" + + "m5oyUFvrxvQrMB+fss8rYkwbZZhwK76u04tf2ZQdZh/2rcpl/7JR0fMUvO0IYfow\n" + + "7GduISnlrLoDpst1lPk8YM75sq7uRe3Gqt0x+EHuHzf9Y8z/POu7AYo9Yxs9SYp5\n" + + "NIcEu0GfAgMBAAECggEAcYsagcX6o01BdfoX6nzZRMJ7mlN28FLKbQZLChOmJjpw\n" + + "e4alQNoMqfsbK0g89gscKoclBNXLj19OihrFQjbKCcpJUCVLhz+cLpUun7hZ7RdZ\n" + + "X1AyDloz4pXYa4jv9ROLfT7lXA2erOytbzm4yV+TQJBqH/qebcfnQYvbfShTmJcp\n" + + "fH2lNYhn5g3+jHb79aakwGTg9q8b88lkDL7gB66jvoEBe3JtCItplXuET5UfrDI/\n" + + "8+ef1n2vMqPc6GIyCrD0p4JV90D3OBOWq41V+AwbOKFJ8kGKJ0d5W0SxQJL6F9IV\n" + + "rg4zx4mXRxq5cWKLiXd2qAu97n7d9g7KbOy6UPMigQKBgQDj8VJGeEn0wth/WmUG\n" + + "RTh4t1R5lrFAZ5ZuM2OZ4r5qjC6o8GUlHwXovc3kcz1whFI0MvOq1rdZkO+tvtvO\n" + + "kcsJfOK4Xfoi/TyhKoYZjXbTEAlTE1HwckaTfNex2B02dfiv11nRJ57bEwbhL3V7\n" + + "rzaOJl+0KXdbG00W2Ip7AJ8AxwKBgQDTK1fz0p90HDPM+V2YuTtO/VavD5vJj5CJ\n" + + "2HYezM9l4Lp/7r+++PzjuzikpflhTUeijxNyOFGKtH8KEpEtyVGx1UBjK8VwM4sX\n" + + "7k+GZ2e3upisagV/GisnEB7lhOnoLUqD8x7xTRHx2RBdw44wUqUGmC/zZ552DHrR\n" + + "hvNhKEyQaQKBgQDFNr+WlPB3wjUKSq1pdW5ck1GVOVn2fSlcAz5DoDhbexnLtOHt\n" + + "8h9stPt0kngv52wwGX1U7B0KcynLy3vmB6IBfXmzRivrJerVDjOj3A9YoWFP7UFR\n" + + "pa2GYddE2dS8j+kwSkQ9f+gjZxzmq+cbsgajinP3LoFD5CUYhRWbQnhPdQKBgDZw\n" + + "IxFhR+gH6Ta7Rmy7u9VmK/WfYXr5vro6imDwTbsmzw1yAA58Y71Vo4mWnA6AfKok\n" + + "lk/IwwSt+V4gYTrbfmsI3btzKkf9kasOrYOpnqxXt0ojXt1gYqWEW2Kx/Bb1rhMM\n" + + "Fvr/8lNVsQlrA3njpFVp4FqwaMJn/zWKw61VVT+ZAoGAOkcDDz6GihRX8CkK5ejh\n" + + "qV/vI/m42Qsg2OddE4yUvAHpki1gEmqK9scULrsyztCGtSzx+l3TibzmG/bGbsTJ\n" + + "1HzQiotarX2fSCAgA8wZvc4F0eQbVo5gxDrsRKIwMSgr1GrEfqd93yuKMDp4TifH\n" + + "P54N1bX5PnvnE2HC22dRMNQ=\n" + + "-----END PRIVATE KEY-----\n"; + BufferedReader reader = new BufferedReader(new StringReader(pem)); + Key key = PemKeyType.RSA_PSS_2048_SHA256.readKey(reader); + assertThat(key).isNotNull(); + assertThat(key).isInstanceOf(RSAPrivateKey.class); + RSAPrivateKey rsa = (RSAPrivateKey) key; + assertThat(rsa.getModulus()).isNotNull(); + assertThat(rsa.getPrivateExponent()).isNotNull(); + } + + @Test + public void readKey_EcPublicKey_shouldWork() throws Exception { + String pem = + "-----BEGIN PUBLIC KEY-----\n" + + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7BiT5K5pivl4Qfrt9hRhRREMUzj/\n" + + "8suEJ7GlMxZfvdcpbi/GhYPuJi8Gn2H1NaMJZcLZo5MLPKyyGT5u3u1VBQ==\n" + + "-----END PUBLIC KEY-----\n"; + BufferedReader reader = new BufferedReader(new StringReader(pem)); + Key key = PemKeyType.ECDSA_P256_SHA256.readKey(reader); + assertThat(key).isNotNull(); + assertThat(key).isInstanceOf(ECPublicKey.class); + } + + @Test + public void readKey_EcPrivateKey_shouldWork() throws Exception { + String pem = + "-----BEGIN PRIVATE KEY-----\n" + + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghpeIjMYdV40aVFTt\n" + + "u8kJPLduSnj6HBamgrrZwAhKLrahRANCAAThRzShRQmj7MChwiZWH6k6PpksS5HM\n" + + "8xP2XD/CiUeWCLR8g30Zh9K7NvufcfZxyJ3I6NTilbGcEM5/VgqAt8z3\n" + + "-----END PRIVATE KEY-----\n"; + BufferedReader reader = new BufferedReader(new StringReader(pem)); + Key key = PemKeyType.ECDSA_P256_SHA256.readKey(reader); + assertThat(key).isNotNull(); + assertThat(key).isInstanceOf(ECPrivateKey.class); + } + + @Test + public void readKey_withCommentHeader_shouldWork() throws Exception { + String pem = + "-----BEGIN PUBLIC KEY-----\n" + + "Version: 1.0.0\n" + + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv90Xf/NN1lRGBofJQzJf\n" + + "lHvo6GAf25GGQGaMmD9T1ZP71CCbJ69lGIS/6akFBg6ECEHGM2EZ4WFLCdr5byUq\n" + + "GCf4mY4WuOn+AcwzwAoDz9ASIFcQOoPclO7JYdfo2SOaumumdb5S/7FkKJ70TGYW\n" + + "j9aTOYWsCcaojbjGDY/JEXz3BSRIngcgOvXBmV1JokcJ/LsrJD263WE9iUknZDhB\n" + + "K7y4ChjHNqL8yJcw/D8xLNiJtIyuxiZ00p/lOVUInr8C/a2C1UGCgEGuXZAEGAdO\n" + + "NVez52n5TLvQP3hRd4MTi7YvfhezRcA4aXyIDOv+TYi4p+OVTYQ+FMbkgoWBm5bq\n" + + "wQIDAQAB\n" + + "-----END PUBLIC KEY-----\n"; + BufferedReader reader = new BufferedReader(new StringReader(pem)); + Key key = PemKeyType.RSA_PSS_2048_SHA256.readKey(reader); + assertThat(key).isNotNull(); + assertThat(key).isInstanceOf(RSAPublicKey.class); + RSAPublicKey rsa = (RSAPublicKey) key; + assertThat(rsa.getModulus()).isNotNull(); + assertThat(rsa.getPublicExponent()).isNotNull(); + } + + @Test + public void readKey_withCommentHeaderOutsideMarkers_shouldWork() throws Exception { + String pem = + "-----BEGIN PUBLIC KEY-----\n" + + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv90Xf/NN1lRGBofJQzJf\n" + + "lHvo6GAf25GGQGaMmD9T1ZP71CCbJ69lGIS/6akFBg6ECEHGM2EZ4WFLCdr5byUq\n" + + "GCf4mY4WuOn+AcwzwAoDz9ASIFcQOoPclO7JYdfo2SOaumumdb5S/7FkKJ70TGYW\n" + + "j9aTOYWsCcaojbjGDY/JEXz3BSRIngcgOvXBmV1JokcJ/LsrJD263WE9iUknZDhB\n" + + "K7y4ChjHNqL8yJcw/D8xLNiJtIyuxiZ00p/lOVUInr8C/a2C1UGCgEGuXZAEGAdO\n" + + "NVez52n5TLvQP3hRd4MTi7YvfhezRcA4aXyIDOv+TYi4p+OVTYQ+FMbkgoWBm5bq\n" + + "wQIDAQAB\n" + + "-----END PUBLIC KEY-----\n" + + "Version: 1.0.0\n"; + BufferedReader reader = new BufferedReader(new StringReader(pem)); + Key key = PemKeyType.RSA_PSS_2048_SHA256.readKey(reader); + assertThat(key).isNotNull(); + assertThat(key).isInstanceOf(RSAPublicKey.class); + RSAPublicKey rsa = (RSAPublicKey) key; + assertThat(rsa.getModulus()).isNotNull(); + assertThat(rsa.getPublicExponent()).isNotNull(); + } + + @Test + public void readKey_withBEGIN_RSA_PUBLIC_KEY_shouldWork() throws Exception { + String pem = + "-----BEGIN RSA PUBLIC KEY-----\n" + + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv90Xf/NN1lRGBofJQzJf\n" + + "lHvo6GAf25GGQGaMmD9T1ZP71CCbJ69lGIS/6akFBg6ECEHGM2EZ4WFLCdr5byUq\n" + + "GCf4mY4WuOn+AcwzwAoDz9ASIFcQOoPclO7JYdfo2SOaumumdb5S/7FkKJ70TGYW\n" + + "j9aTOYWsCcaojbjGDY/JEXz3BSRIngcgOvXBmV1JokcJ/LsrJD263WE9iUknZDhB\n" + + "K7y4ChjHNqL8yJcw/D8xLNiJtIyuxiZ00p/lOVUInr8C/a2C1UGCgEGuXZAEGAdO\n" + + "NVez52n5TLvQP3hRd4MTi7YvfhezRcA4aXyIDOv+TYi4p+OVTYQ+FMbkgoWBm5bq\n" + + "wQIDAQAB\n" + + "-----END RSA PUBLIC KEY-----\n"; + BufferedReader reader = new BufferedReader(new StringReader(pem)); + Key key = PemKeyType.RSA_PSS_2048_SHA256.readKey(reader); + assertThat(key).isNotNull(); + assertThat(key).isInstanceOf(RSAPublicKey.class); + RSAPublicKey rsa = (RSAPublicKey) key; + assertThat(rsa.getModulus()).isNotNull(); + assertThat(rsa.getPublicExponent()).isNotNull(); + } +} diff --git a/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPkcs1SignJceTest.java b/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPkcs1SignJceTest.java index 2c4de17a5..69d621e22 100644 --- a/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPkcs1SignJceTest.java +++ b/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPkcs1SignJceTest.java @@ -48,7 +48,7 @@ public class RsaSsaPkcs1SignJceTest { fail("Unsafe hash, should have thrown exception."); } catch (GeneralSecurityException e) { // Expected. - TestUtil.assertExceptionContains(e, "SHA1 is not safe"); + TestUtil.assertExceptionContains(e, "Unsupported hash: SHA1"); } } diff --git a/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPkcs1VerifyJceTest.java b/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPkcs1VerifyJceTest.java index 2ba79599e..a3df816d3 100644 --- a/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPkcs1VerifyJceTest.java +++ b/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPkcs1VerifyJceTest.java @@ -48,7 +48,7 @@ public class RsaSsaPkcs1VerifyJceTest { fail("Unsafe hash, should have thrown exception."); } catch (GeneralSecurityException e) { // Expected. - TestUtil.assertExceptionContains(e, "SHA1 is not safe"); + TestUtil.assertExceptionContains(e, "Unsupported hash: SHA1"); } } diff --git a/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPssSignJceTest.java b/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPssSignJceTest.java index 6a9f1fa89..b22612dcb 100644 --- a/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPssSignJceTest.java +++ b/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPssSignJceTest.java @@ -47,7 +47,7 @@ public class RsaSsaPssSignJceTest { fail("Unsafe hash, should have thrown exception."); } catch (GeneralSecurityException e) { // Expected. - TestUtil.assertExceptionContains(e, "SHA1 is not safe"); + TestUtil.assertExceptionContains(e, "Unsupported hash: SHA1"); } } diff --git a/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPssVerifyJceTest.java b/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPssVerifyJceTest.java index cfb6789a0..ed15e285e 100644 --- a/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPssVerifyJceTest.java +++ b/java/src/test/java/com/google/crypto/tink/subtle/RsaSsaPssVerifyJceTest.java @@ -47,7 +47,7 @@ public class RsaSsaPssVerifyJceTest { fail("Unsafe hash, should have thrown exception."); } catch (GeneralSecurityException e) { // Expected. - TestUtil.assertExceptionContains(e, "SHA1 is not safe"); + TestUtil.assertExceptionContains(e, "Unsupported hash: SHA1"); } } diff --git a/java/src/test/java/com/google/crypto/tink/subtle/ValidatorsTest.java b/java/src/test/java/com/google/crypto/tink/subtle/ValidatorsTest.java index 16d69a82c..96b6d2942 100644 --- a/java/src/test/java/com/google/crypto/tink/subtle/ValidatorsTest.java +++ b/java/src/test/java/com/google/crypto/tink/subtle/ValidatorsTest.java @@ -142,7 +142,7 @@ public class ValidatorsTest { Validators.validateSignatureHash(HashType.SHA1); fail("Expected GeneralSecurityException"); } catch (GeneralSecurityException e) { - TestUtil.assertExceptionContains(e, "SHA1 is not safe"); + TestUtil.assertExceptionContains(e, "Unsupported hash: SHA1"); } } diff --git a/proto/common.proto b/proto/common.proto index 393e415f6..41e1b6df1 100644 --- a/proto/common.proto +++ b/proto/common.proto @@ -43,6 +43,7 @@ enum EcPointFormat { enum HashType { UNKNOWN_HASH = 0; SHA1 = 1; // Using SHA1 for digital signature is deprecated but HMAC-SHA1 is fine. + SHA384 = 2; SHA256 = 3; SHA512 = 4; }; -- GitLab