public void process(Exchange exchange) throws Exception { Signature signer = createSignatureService(); Certificate cert = getCertificate(exchange); if (cert == null) { PublicKey pk = getPublicKeyOrCertificateFromHeader(exchange, PublicKey.class, config.getPublicKey()); if (pk == null) { throw new IllegalStateException(String.format("Cannot verify signature as no Public Key or Certificate has been supplied." + " Either supply one in the route definition or via the message header '%s'", DigitalSignatureConstants.SIGNATURE_PUBLIC_KEY_OR_CERT)); } signer.initVerify(pk); } else { signer.initVerify(cert); } calculateSignature(exchange, signer); byte[] signature = getSignatureFromExchange(exchange); if (!signer.verify(signature)) { throw new SignatureException("Cannot verify signature of exchange"); } clearMessageHeaders(exchange.getIn()); }
protected String getAlias(Exchange exchange) throws Exception { KeyStore keystore = config.getKeystore(); if (keystore != null) { String alias = exchange.getIn().getHeader(DigitalSignatureConstants.KEYSTORE_ALIAS, String.class); if (alias == null) { alias = config.getAlias(); } // if there is only one entry then use it. Document this well if (alias == null && keystore.size() == 1) { alias = keystore.aliases().nextElement(); } return alias; } return null; }
@Override public void configure() throws Exception { from("direct:sign_a") .to("crypto:sign://usingKeystore?keystore=#keyStore&alias=system_a&password=keyPasswordA") .setHeader("sendingSystem", constant("a")) .to("direct:verify"); from("direct:sign_b") .to("crypto:sign://usingKeystore?keystore=#keyStore&alias=system_b&password=keyPasswordB") .setHeader("sendingSystem", constant("b")) .to("direct:verify"); from("direct:verify") .log("Verifying message") .setHeader(DigitalSignatureConstants.KEYSTORE_ALIAS, simple("system_${header[sendingSystem]}")) .to("crypto:verify://usingKeystore?keystore=#trustStore") .log("Message verified") .to("mock:verified"); }
@Test public void testMessageSigningMismatchedKeys() throws InterruptedException { MockEndpoint mockVerified = getMockEndpoint("mock:verified"); mockVerified.setExpectedMessageCount(0); MockEndpoint mockSigned = getMockEndpoint("mock:signed"); mockSigned.whenAnyExchangeReceived(new Processor() { @Override public void process(Exchange exchange) throws Exception { // let's override the key used by the verifying endpoint exchange.getIn().setHeader(DigitalSignatureConstants.KEYSTORE_ALIAS, "system_b"); } }); try { template.sendBody("direct:sign", "foo"); fail(); } catch (CamelExecutionException cex) { assertTrue(ExceptionUtils.getRootCause(cex) instanceof SignatureException); String rootCauseMessage = ExceptionUtils.getRootCauseMessage(cex); assertEquals("SignatureException: Cannot verify signature of exchange", rootCauseMessage); } }
private <T> T getPublicKeyOrCertificateFromHeader(Exchange exchange, Class<? extends T> verificationType, T defaultsTo) { T pkOrCert = exchange.getIn().getHeader(DigitalSignatureConstants.SIGNATURE_PUBLIC_KEY_OR_CERT, verificationType); if (pkOrCert == null) { pkOrCert = defaultsTo; } return pkOrCert; }
protected void clearMessageHeaders(Message in) { if (config.isClearHeaders()) { Map<String, Object> headers = in.getHeaders(); for (Field f : DigitalSignatureConstants.class.getFields()) { headers.remove(ObjectHelper.lookupConstantFieldValue(DigitalSignatureConstants.class, f.getName())); } } }
private PrivateKey getPrivateKeyFromKeystoreOrExchange(Exchange exchange) throws Exception { PrivateKey pk = config.getPrivateKey(getAlias(exchange), getKeyPassword(exchange)); if (pk == null) { pk = exchange.getIn().getHeader(DigitalSignatureConstants.SIGNATURE_PRIVATE_KEY, PrivateKey.class); if (pk == null) { throw new IllegalStateException(format("Cannot sign message as no Private Key has been supplied. " + "Either supply one in the route definition sign(keystore, alias) or sign(privateKey) " + "or via the message header '%s'", DigitalSignatureConstants.SIGNATURE_PRIVATE_KEY)); } } return pk; }
protected char[] getKeyPassword(Exchange exchange) throws Exception { KeyStore keystore = config.getKeystore(); char[] password = null; if (keystore != null) { password = exchange.getIn().getHeader(DigitalSignatureConstants.KEYSTORE_PASSWORD, char[].class); if (password == null) { password = config.getPassword(); } } return password; }
@Test public void testMessageSigningMissingKey() throws InterruptedException { MockEndpoint mockVerified = getMockEndpoint("mock:verified"); mockVerified.setExpectedMessageCount(0); try { template.sendBodyAndHeader("direct:sign", "foo", DigitalSignatureConstants.KEYSTORE_ALIAS, "cheese"); fail(); } catch (CamelExecutionException cex) { assertTrue(ExceptionUtils.getRootCause(cex) instanceof IllegalStateException); String rootCauseMessage = ExceptionUtils.getRootCauseMessage(cex); assertTrue(rootCauseMessage.startsWith("IllegalStateException: Cannot sign message as no Private Key has been supplied.")); } }
@Test public void testBasicSignatureRoute() throws Exception { CamelContext camelctx = new DefaultCamelContext(); camelctx.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { from("direct:sign") .to("crypto:sign://basic?privateKey=#myPrivateKey") .to("direct:verify"); from("direct:verify") .to("crypto:verify://basic?publicKey=#myPublicKey") .to("mock:result"); } }); camelctx.start(); try { camelctx.createProducerTemplate().sendBody("direct:sign", PAYLOAD); MockEndpoint mockEndpoint = camelctx.getEndpoint("mock:result", MockEndpoint.class); Exchange e = mockEndpoint.getExchanges().get(0); Message result = e == null ? null : e.hasOut() ? e.getOut() : e.getIn(); Assert.assertNull(result.getHeader(DigitalSignatureConstants.SIGNATURE)); } finally { camelctx.stop(); } }