package at.gv.egiz.eaaf.modules.auth.sl20.utils; import java.io.IOException; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.Provider; import java.security.Security; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import org.apache.commons.lang3.RandomStringUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.jose4j.base64url.Base64Url; import org.jose4j.jca.ProviderContext; import org.jose4j.jwa.AlgorithmConstraints; import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers; import org.jose4j.jwe.JsonWebEncryption; import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers; import org.jose4j.lang.JoseException; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.fasterxml.jackson.databind.JsonNode; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap; import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("/spring/test_eaaf_sl20_hsm.beans.xml") public abstract class AbstractJsonSecurityUtilsTest { @Autowired protected DummyAuthConfigMap config; @Autowired protected IJoseTools joseTools; @Autowired protected EaafKeyStoreFactory keyStoreFactory; @BeforeClass public static void classInitializer() { Security.addProvider(new BouncyCastleProvider()); } protected abstract void setRsaSigningKey(); protected abstract void setEcSigningKey(); protected abstract void setRsaEncryptionKey(); protected abstract void setEcEncryptionKey(); protected abstract Pair getEncryptionKeyStore() throws EaafException; protected abstract String getRsaKeyAlias(); protected abstract String getRsaKeyPassword(); protected abstract String getEcKeyAlias(); protected abstract String getEcKeyPassword(); @Test public void fullEncryptDecrypt() throws JoseException, EaafException { final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}"; final JsonWebEncryption jwe = new JsonWebEncryption(); jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.ECDH_ES_A256KW); jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM); jwe.setKey(JoseUtils.convertToBcKeyIfRequired(joseTools.getEncryptionCertificate().getPublicKey())); jwe.setX509CertSha256ThumbprintHeaderValue(joseTools.getEncryptionCertificate()); jwe.setPayload(payLoad); // set special provider if required final Pair rsaEncKeyStore = getEncryptionKeyStore(); if (rsaEncKeyStore.getSecond() != null) { final ProviderContext providerCtx = new ProviderContext(); providerCtx.getSuppliedKeyProviderContext().setSignatureProvider( rsaEncKeyStore.getSecond().getName()); jwe.setProviderContext(providerCtx); } final String encData = jwe.getCompactSerialization(); Assert.assertNotNull("JWE Encryption", encData); final JsonNode decData = joseTools.decryptPayload(encData); Assert.assertNotNull("JWE Decryption", decData); } @Test public void encryptionRsa() throws JoseException, EaafException { final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}"; final Pair rsaEncKeyStore = getEncryptionKeyStore(); final Pair key = EaafKeyStoreUtils.getPrivateKeyAndCertificates( rsaEncKeyStore.getFirst(), getRsaKeyAlias(), getRsaKeyPassword().toCharArray(), true, "jUnit RSA JWE"); final JsonWebEncryption jwe = new JsonWebEncryption(); jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.RSA_OAEP_256); jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM); jwe.setKey(key.getSecond()[0].getPublicKey()); jwe.setPayload(payLoad); // set special provider if required if (rsaEncKeyStore.getSecond() != null) { final ProviderContext providerCtx = new ProviderContext(); providerCtx.getSuppliedKeyProviderContext().setSignatureProvider( rsaEncKeyStore.getSecond().getName()); jwe.setProviderContext(providerCtx); } final String encData = jwe.getCompactSerialization(); Assert.assertNotNull("JWE", encData); } @Test public void encryptionEc() throws JoseException, EaafException { final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}"; final Pair rsaEncKeyStore = getEncryptionKeyStore(); final Pair key = EaafKeyStoreUtils.getPrivateKeyAndCertificates( rsaEncKeyStore.getFirst(), getEcKeyAlias(), getEcKeyPassword().toCharArray(), true, "jUnit RSA JWE"); final JsonWebEncryption jwe = new JsonWebEncryption(); jwe.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.ECDH_ES_A256KW); jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_128_GCM); jwe.setKey(JoseUtils.convertToBcKeyIfRequired(key.getSecond()[0].getPublicKey())); jwe.setPayload(payLoad); // set special provider if required if (rsaEncKeyStore.getSecond() != null) { final ProviderContext providerCtx = new ProviderContext(); providerCtx.getSuppliedKeyProviderContext().setSignatureProvider( rsaEncKeyStore.getSecond().getName()); jwe.setProviderContext(providerCtx); } final String encData = jwe.getCompactSerialization(); Assert.assertNotNull("JWE", encData); } @Test public void noTrustedCert() throws CertificateEncodingException, KeyStoreException, JoseException, IOException, EaafException { setRsaSigningKey(); setRsaEncryptionKey(); final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}"; final String jws = joseTools.createSignature(payLoad); Assert.assertNotNull("Signed msg", jws); try { joseTools.validateSignature( jws, keyStoreFactory.buildNewKeyStore(getSigTrustStoreConfigOnlyEc()).getFirst(), getDefaultAlgorithmConstrains()); Assert.fail("Wrong JOSE Sig not detected"); } catch (final JoseException e) { Assert.assertEquals("Wrong errorCode", "Can NOT select verification key for JWS. Signature verification FAILED", e.getMessage()); } } @Test public void invalidSignature() throws CertificateEncodingException, KeyStoreException, JoseException, IOException, EaafException { setRsaSigningKey(); setRsaEncryptionKey(); final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}"; final String jws = joseTools.createSignature(payLoad); Assert.assertNotNull("Signed msg", jws); final String invalidJws = jws.substring(0, jws.indexOf(".")) + "." + Base64Url.encodeUtf8ByteRepresentation("{\"aac\":\"" + RandomStringUtils.randomAlphabetic(25) + "\"}") + "." + jws.substring(jws.lastIndexOf(".") + 1); final VerificationResult result = joseTools.validateSignature( invalidJws, keyStoreFactory.buildNewKeyStore(getSigTrustStoreConfigValid()).getFirst(), getDefaultAlgorithmConstrains()); Assert.assertFalse("wrong sig. verification state", result.isValidSigned()); } @Test public void validSigningRsa() throws CertificateEncodingException, KeyStoreException, JoseException, IOException, EaafException { setRsaSigningKey(); setRsaEncryptionKey(); final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}"; final String jws = joseTools.createSignature(payLoad); Assert.assertNotNull("Signed msg", jws); final VerificationResult verify = joseTools.validateSignature( jws, keyStoreFactory.buildNewKeyStore(getSigTrustStoreConfigValid()).getFirst(), getDefaultAlgorithmConstrains()); Assert.assertTrue("wrong verify state", verify.isValidSigned()); Assert.assertNotNull("JWS Header", verify.getJoseHeader()); Assert.assertNotNull("JWS Payload", verify.getPayload()); Assert.assertNotNull("CertChain", verify.getCertChain()); } @Test public void validSigningEc() throws CertificateEncodingException, KeyStoreException, JoseException, IOException, EaafException { setEcSigningKey(); setEcEncryptionKey(); final String payLoad = "{\"aac\":\"" + RandomStringUtils.randomAlphanumeric(100) + "\"}"; final String jws = joseTools.createSignature(payLoad); Assert.assertNotNull("Signed msg", jws); final VerificationResult verify = joseTools.validateSignature( jws, keyStoreFactory.buildNewKeyStore(getSigTrustStoreConfigValid()).getFirst(), getDefaultAlgorithmConstrains()); Assert.assertTrue("wrong verify state", verify.isValidSigned()); Assert.assertNotNull("JWS Header", verify.getJoseHeader()); Assert.assertNotNull("JWS Payload", verify.getPayload()); Assert.assertNotNull("CertChain", verify.getCertChain()); } protected KeyStoreConfiguration getSigTrustStoreConfigValid() { final KeyStoreConfiguration trustConfig = new KeyStoreConfiguration(); trustConfig.setFriendlyName("jUnit TrustStore"); trustConfig.setKeyStoreType(KeyStoreType.JKS); trustConfig.setSoftKeyStoreFilePath("src/test/resources/data/junit.jks"); trustConfig.setSoftKeyStorePassword("password"); return trustConfig; } protected KeyStoreConfiguration getSigTrustStoreConfigOnlyEc() { final KeyStoreConfiguration trustConfig = new KeyStoreConfiguration(); trustConfig.setFriendlyName("jUnit TrustStore"); trustConfig.setKeyStoreType(KeyStoreType.JKS); trustConfig.setSoftKeyStoreFilePath("src/test/resources/data/junit_no_rsa.jks"); trustConfig.setSoftKeyStorePassword("password"); return trustConfig; } private AlgorithmConstraints getDefaultAlgorithmConstrains() { return new AlgorithmConstraints(ConstraintType.WHITELIST, SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING .toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()])); } }