Remove private/public key match verification.
Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>
This commit is contained in:
parent
45e3fc86a6
commit
3049810a35
|
|
@ -10,10 +10,6 @@ import java.security.InvalidKeyException;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.security.Signature;
|
|
||||||
import java.security.SignatureException;
|
|
||||||
import java.security.cert.CertPathValidator;
|
import java.security.cert.CertPathValidator;
|
||||||
import java.security.cert.CertPathValidatorException;
|
import java.security.cert.CertPathValidatorException;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
|
|
@ -44,10 +40,6 @@ import static org.apache.commons.lang3.StringUtils.startsWith;
|
||||||
*/
|
*/
|
||||||
public class CertificateUtils {
|
public class CertificateUtils {
|
||||||
|
|
||||||
// Algorithms for verifying private and public keys
|
|
||||||
private static final String SHA_512_WITH_ECDSA = "SHA512withECDSA";
|
|
||||||
private static final String SHA_512_WITH_RSA = "SHA512withRSA";
|
|
||||||
|
|
||||||
private static final String SPIFFE_PREFIX = "spiffe://";
|
private static final String SPIFFE_PREFIX = "spiffe://";
|
||||||
private static final int SAN_VALUE_INDEX = 1;
|
private static final int SAN_VALUE_INDEX = 1;
|
||||||
private static final String PUBLIC_KEY_INFRASTRUCTURE_ALGORITHM = "PKIX";
|
private static final String PUBLIC_KEY_INFRASTRUCTURE_ALGORITHM = "PKIX";
|
||||||
|
|
@ -154,24 +146,6 @@ public class CertificateUtils {
|
||||||
return spiffeId.getTrustDomain();
|
return spiffeId.getTrustDomain();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates that the private key and the public key in the x509Certificate match by
|
|
||||||
* creating a signature with the private key and verifying with the public key.
|
|
||||||
*
|
|
||||||
* @throws InvalidKeyException if the keys don't match
|
|
||||||
*/
|
|
||||||
public static void validatePrivateKey(final PrivateKey privateKey, final X509Certificate x509Certificate) throws InvalidKeyException {
|
|
||||||
AsymmetricKeyAlgorithm algorithm = AsymmetricKeyAlgorithm.parse(privateKey.getAlgorithm());
|
|
||||||
|
|
||||||
switch (algorithm) {
|
|
||||||
case RSA:
|
|
||||||
verifyKeys(privateKey, x509Certificate.getPublicKey(), SHA_512_WITH_RSA);
|
|
||||||
break;
|
|
||||||
case EC:
|
|
||||||
verifyKeys(privateKey, x509Certificate.getPublicKey(), SHA_512_WITH_ECDSA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isCA(final X509Certificate cert) {
|
public static boolean isCA(final X509Certificate cert) {
|
||||||
return cert.getBasicConstraints() != -1;
|
return cert.getBasicConstraints() != -1;
|
||||||
}
|
}
|
||||||
|
|
@ -202,23 +176,6 @@ public class CertificateUtils {
|
||||||
return keySpec;
|
return keySpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyKeys(final PrivateKey privateKey, final PublicKey publicKey, final String algorithm) throws InvalidKeyException {
|
|
||||||
final byte[] challenge = new SecureRandom().generateSeed(100);
|
|
||||||
try {
|
|
||||||
Signature sig = Signature.getInstance(algorithm);
|
|
||||||
sig.initSign(privateKey);
|
|
||||||
sig.update(challenge);
|
|
||||||
byte[] signature = sig.sign();
|
|
||||||
sig.initVerify(publicKey);
|
|
||||||
sig.update(challenge);
|
|
||||||
if (!sig.verify(signature)) {
|
|
||||||
throw new InvalidKeyException("Private Key does not match Certificate Public Key");
|
|
||||||
}
|
|
||||||
} catch (NoSuchAlgorithmException | SignatureException e) {
|
|
||||||
throw new InvalidKeyException("Private and Public Keys could not be verified", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> getSpiffeIds(final X509Certificate certificate) throws CertificateParsingException {
|
private static List<String> getSpiffeIds(final X509Certificate certificate) throws CertificateParsingException {
|
||||||
if (certificate.getSubjectAlternativeNames() == null) {
|
if (certificate.getSubjectAlternativeNames() == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,6 @@ public class X509Svid {
|
||||||
val privateKey = generatePrivateKey(privateKeyBytes, keyFileFormat, x509Certificates);
|
val privateKey = generatePrivateKey(privateKeyBytes, keyFileFormat, x509Certificates);
|
||||||
val spiffeId = getSpiffeId(x509Certificates);
|
val spiffeId = getSpiffeId(x509Certificates);
|
||||||
|
|
||||||
validatePrivateKey(privateKey, x509Certificates);
|
|
||||||
validateLeafCertificate(x509Certificates.get(0));
|
validateLeafCertificate(x509Certificates.get(0));
|
||||||
|
|
||||||
// there are intermediate CA certificates
|
// there are intermediate CA certificates
|
||||||
|
|
@ -225,13 +224,4 @@ public class X509Svid {
|
||||||
throw new X509SvidException("Leaf certificate must not have 'cRLSign' as key usage");
|
throw new X509SvidException("Leaf certificate must not have 'cRLSign' as key usage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validatePrivateKey(final PrivateKey privateKey, final List<X509Certificate> x509Certificates)
|
|
||||||
throws X509SvidException {
|
|
||||||
try {
|
|
||||||
CertificateUtils.validatePrivateKey(privateKey, x509Certificates.get(0));
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new X509SvidException("Private Key does not match Certificate Public Key", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
public class X509SvidTest {
|
class X509SvidTest {
|
||||||
|
|
||||||
static String keyRSA = "testdata/x509svid/key-pkcs8-rsa.pem";
|
static String keyRSA = "testdata/x509svid/key-pkcs8-rsa.pem";
|
||||||
static String keyRSAOther = "testdata/x509svid/key-rsa-other.pem";
|
|
||||||
static String certSingle = "testdata/x509svid/good-leaf-only.pem";
|
static String certSingle = "testdata/x509svid/good-leaf-only.pem";
|
||||||
static String leafNoDigitalSignature = "testdata/x509svid/wrong-leaf-no-digital-signature.pem";
|
static String leafNoDigitalSignature = "testdata/x509svid/wrong-leaf-no-digital-signature.pem";
|
||||||
static String leafCRLSign = "testdata/x509svid/wrong-leaf-crl-sign.pem";
|
static String leafCRLSign = "testdata/x509svid/wrong-leaf-crl-sign.pem";
|
||||||
|
|
@ -39,7 +38,6 @@ public class X509SvidTest {
|
||||||
static String keyECDSA = "testdata/x509svid/key-pkcs8-ecdsa.pem";
|
static String keyECDSA = "testdata/x509svid/key-pkcs8-ecdsa.pem";
|
||||||
static String certMultiple = "testdata/x509svid/good-leaf-and-intermediate.pem";
|
static String certMultiple = "testdata/x509svid/good-leaf-and-intermediate.pem";
|
||||||
static String corrupted = "testdata/x509svid/corrupted";
|
static String corrupted = "testdata/x509svid/corrupted";
|
||||||
static String keyECDSAOther = "testdata/x509svid/key-ecdsa-other.pem";
|
|
||||||
static String keyDER = "testdata/x509svid/keyEC.der";
|
static String keyDER = "testdata/x509svid/keyEC.der";
|
||||||
static String certDER = "testdata/x509svid/cert.der";
|
static String certDER = "testdata/x509svid/cert.der";
|
||||||
|
|
||||||
|
|
@ -99,23 +97,7 @@ public class X509SvidTest {
|
||||||
),
|
),
|
||||||
Arguments.of(TestCase
|
Arguments.of(TestCase
|
||||||
.builder()
|
.builder()
|
||||||
.name("7. Certificate does not match private key: RSA keys")
|
.name("7. Certificate without SPIFFE ID")
|
||||||
.certsPath(certSingle)
|
|
||||||
.keyPath(keyRSAOther)
|
|
||||||
.expectedError("Private Key does not match Certificate Public Key")
|
|
||||||
.build()
|
|
||||||
),
|
|
||||||
Arguments.of(TestCase
|
|
||||||
.builder()
|
|
||||||
.name("8. Certificate does not match private key: EC keys")
|
|
||||||
.certsPath(certMultiple)
|
|
||||||
.keyPath(keyECDSAOther)
|
|
||||||
.expectedError("Private Key does not match Certificate Public Key")
|
|
||||||
.build()
|
|
||||||
),
|
|
||||||
Arguments.of(TestCase
|
|
||||||
.builder()
|
|
||||||
.name("9. Certificate without SPIFFE ID")
|
|
||||||
.certsPath(leafEmptyID)
|
.certsPath(leafEmptyID)
|
||||||
.keyPath(keyRSA)
|
.keyPath(keyRSA)
|
||||||
.expectedError("Certificate does not contain SPIFFE ID in the URI SAN")
|
.expectedError("Certificate does not contain SPIFFE ID in the URI SAN")
|
||||||
|
|
@ -123,7 +105,7 @@ public class X509SvidTest {
|
||||||
),
|
),
|
||||||
Arguments.of(TestCase
|
Arguments.of(TestCase
|
||||||
.builder()
|
.builder()
|
||||||
.name("10. Leaf certificate with CA flag set to true")
|
.name("8. Leaf certificate with CA flag set to true")
|
||||||
.certsPath(leafCAtrue)
|
.certsPath(leafCAtrue)
|
||||||
.keyPath(keyRSA)
|
.keyPath(keyRSA)
|
||||||
.expectedError("Leaf certificate must not have CA flag set to true")
|
.expectedError("Leaf certificate must not have CA flag set to true")
|
||||||
|
|
@ -131,7 +113,7 @@ public class X509SvidTest {
|
||||||
),
|
),
|
||||||
Arguments.of(TestCase
|
Arguments.of(TestCase
|
||||||
.builder()
|
.builder()
|
||||||
.name("11. Leaf certificate without digitalSignature as key usage")
|
.name("9. Leaf certificate without digitalSignature as key usage")
|
||||||
.certsPath(leafNoDigitalSignature)
|
.certsPath(leafNoDigitalSignature)
|
||||||
.keyPath(keyRSA)
|
.keyPath(keyRSA)
|
||||||
.expectedError("Leaf certificate must have 'digitalSignature' as key usage")
|
.expectedError("Leaf certificate must have 'digitalSignature' as key usage")
|
||||||
|
|
@ -139,7 +121,7 @@ public class X509SvidTest {
|
||||||
),
|
),
|
||||||
Arguments.of(TestCase
|
Arguments.of(TestCase
|
||||||
.builder()
|
.builder()
|
||||||
.name("12. Leaf certificate with certSign as key usage")
|
.name("10. Leaf certificate with certSign as key usage")
|
||||||
.certsPath(leafCertSign)
|
.certsPath(leafCertSign)
|
||||||
.keyPath(keyRSA)
|
.keyPath(keyRSA)
|
||||||
.expectedError("Leaf certificate must not have 'keyCertSign' as key usage")
|
.expectedError("Leaf certificate must not have 'keyCertSign' as key usage")
|
||||||
|
|
@ -147,7 +129,7 @@ public class X509SvidTest {
|
||||||
),
|
),
|
||||||
Arguments.of(TestCase
|
Arguments.of(TestCase
|
||||||
.builder()
|
.builder()
|
||||||
.name("13. Leaf certificate with cRLSign as key usage")
|
.name("11. Leaf certificate with cRLSign as key usage")
|
||||||
.certsPath(leafCRLSign)
|
.certsPath(leafCRLSign)
|
||||||
.keyPath(keyRSA)
|
.keyPath(keyRSA)
|
||||||
.expectedError("Leaf certificate must not have 'cRLSign' as key usage")
|
.expectedError("Leaf certificate must not have 'cRLSign' as key usage")
|
||||||
|
|
@ -155,7 +137,7 @@ public class X509SvidTest {
|
||||||
),
|
),
|
||||||
Arguments.of(TestCase
|
Arguments.of(TestCase
|
||||||
.builder()
|
.builder()
|
||||||
.name("14. Signing certificate without CA flag")
|
.name("12. Signing certificate without CA flag")
|
||||||
.certsPath(signNoCA)
|
.certsPath(signNoCA)
|
||||||
.keyPath(keyRSA)
|
.keyPath(keyRSA)
|
||||||
.expectedError("Signing certificate must have CA flag set to true")
|
.expectedError("Signing certificate must have CA flag set to true")
|
||||||
|
|
@ -163,7 +145,7 @@ public class X509SvidTest {
|
||||||
),
|
),
|
||||||
Arguments.of(TestCase
|
Arguments.of(TestCase
|
||||||
.builder()
|
.builder()
|
||||||
.name("15. Signing certificate without CA flag")
|
.name("13. Signing certificate without CA flag")
|
||||||
.certsPath(signNoKeyCertSign)
|
.certsPath(signNoKeyCertSign)
|
||||||
.keyPath(keyRSA)
|
.keyPath(keyRSA)
|
||||||
.expectedError("Signing certificate must have 'keyCertSign' as key usage")
|
.expectedError("Signing certificate must have 'keyCertSign' as key usage")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue