How does Wss4jSecurityInterceptor sign and encrypt SOAP messages, and what infrastructure does that require?
answer
- Signature=integrity/authenticity (private-key sign, public-key verify)
- Encrypt=confidentiality (recipient public wraps symmetric key)
- Crypto/Merlin -> JKS/PKCS12 keystore + truststore
- securementSignatureCrypto/username; securementEncryptionUser=recipient alias
- ordered actions 'Timestamp Signature Encrypt'
basics
~20 sYou add 'Signature' and/or 'Encrypt' to the interceptor's securement/validation actions and supply a WSS4J Crypto (backed by a keystore) plus key aliases and passwords. Signing proves integrity/authenticity with the sender's private key; encryption protects confidentiality using the recipient's public key.
solid answer
~40 sFor signing and encryption Wss4jSecurityInterceptor delegates the crypto to Apache WSS4J's Crypto/Merlin abstraction, which reads a JKS/PKCS12 keystore. To sign outgoing messages you set securementActions to include 'Signature', a setSecurementSignatureCrypto (the keystore), setSecurementUsername (the key alias) and setSecurementPassword (the private-key password); the interceptor produces an XML-DSig signature over the chosen parts. To encrypt you add 'Encrypt', a setSecurementEncryptionCrypto and setSecurementEncryptionUser (the recipient's certificate alias); the payload is encrypted with a symmetric key that is itself wrapped with the recipient's public key. On the receiving side you configure validationActions 'Signature Encrypt', a validationSignatureCrypto (truststore of trusted signer certs) and a validationDecryptionCrypto plus a callback handler that yields the private-key password. Actions are ordered; a typical chain is 'Timestamp Signature Encrypt'.
code
java · 25 lines@Bean
public CryptoFactoryBean signatureCrypto() throws Exception {
CryptoFactoryBean f = new CryptoFactoryBean();
f.setCryptoProvider(org.apache.wss4j.common.crypto.Merlin.class);
f.setKeyStoreType("PKCS12");
f.setKeyStoreLocation(new ClassPathResource("client-keystore.p12"));
f.setKeyStorePassword("storePass");
return f;
}
@Bean
public Wss4jSecurityInterceptor signAndEncrypt(Crypto sigCrypto, Crypto encCrypto) {
Wss4jSecurityInterceptor i = new Wss4jSecurityInterceptor();
i.setSecurementActions("Timestamp Signature Encrypt");
// sign with MY private key
i.setSecurementSignatureCrypto(sigCrypto);
i.setSecurementUsername("client-key"); // my key alias
i.setSecurementPassword("keyPass"); // my private-key password
// encrypt with the RECIPIENT's public cert
i.setSecurementEncryptionCrypto(encCrypto);
i.setSecurementEncryptionUser("server-cert"); // recipient alias in truststore
i.setSecurementEncryptionSymAlgorithm(
"http://www.w3.org/2009/xmlenc11#aes128-gcm");
return i;
}go deeper
Know signing = tamper/authenticity proof, encryption = confidentiality, and both need keys/certificates.
Explain adding Signature/Encrypt actions and that a keystore/truststore (Crypto) is required.
Detail sign-with-private/verify-with-public vs encrypt-with-public/decrypt-with-private, hybrid encryption, and part selection.
Reason about action ordering (sign-then-encrypt), algorithm agility, cert lifecycle/trust, performance, and when WSS beats TLS.
**Two distinct guarantees.** WS-Security offers, beyond authentication: - **Signature** — *integrity* (the message wasn't altered) and *authenticity/non-repudiation* (it came from the holder of a private key). Implemented with **XML Digital Signature (XML-DSig)**: the signer hashes selected elements and signs the hash with their **private key**; the receiver verifies with the signer's **public key/certificate**. - **Encryption** — *confidentiality*. Implemented with **XML Encryption**: the payload is encrypted with a fresh **symmetric session key** (fast), and that session key is then wrapped (encrypted) with the **recipient's public key** so only the recipient's private key can unwrap it (hybrid encryption). The cryptographic *primitives* (RSA, AES, certificate trust) are the Security category's domain; here we care about **how Spring wires WSS4J to perform them**. **The Crypto / keystore layer.** WSS4J abstracts key material behind `org.apache.wss4j.common.crypto.Crypto`, whose default implementation `Merlin` loads a Java **KeyStore** (JKS or PKCS12). You give the interceptor `Crypto` instances via `CryptoFactoryBean` (Spring convenience) or by loading a properties file. Conceptually a party needs: - its **own private key + certificate** (a *keystore*) — to sign outgoing and to decrypt incoming; - its peers' **public certificates** (a *truststore*) — to verify incoming signatures and to encrypt outgoing to a recipient. **Securement (outgoing) config:** - Signing: `setSecurementActions("Signature")`, `setSecurementSignatureCrypto(crypto)`, `setSecurementUsername("myKeyAlias")`, `setSecurementPassword("privKeyPass")`. Optional `setSecurementSignatureParts(...)` selects which elements to sign (e.g. the Body and Timestamp), and `setSecurementSignatureKeyIdentifier("DirectReference")` controls how the cert is referenced in the header. - Encrypting: `setSecurementActions("Encrypt")`, `setSecurementEncryptionCrypto(crypto)`, `setSecurementEncryptionUser("recipientCertAlias")`, plus optional `setSecurementEncryptionParts`, `setSecurementEncryptionSymAlgorithm` (e.g. AES-128-GCM) and `setSecurementEncryptionKeyTransportAlgorithm` (e.g. RSA-OAEP). **Validation (incoming) config:** - Verifying signatures: `setValidationActions("Signature")`, `setValidationSignatureCrypto(truststore)` — WSS4J checks the signature and that the signer cert is trusted. `setValidationSignatureConfirmationEnabled` supports signature confirmation. - Decrypting: include `Encrypt` in `setValidationActions`, `setValidationDecryptionCrypto(myKeystore)`, and a `setValidationCallbackHandler` that returns the **private-key password** (via `WSPasswordCallback` of usage DECRYPT). **Ordering & combining.** The action string is ordered and applied left-to-right on securement; a classic secure chain is `"Timestamp Signature Encrypt"` (sign then encrypt so the signature itself is hidden, and a timestamp for freshness). The receiver lists the matching expected actions. If the actual message doesn't match the expected validation actions, WSS4J raises a security fault. **Gotchas / edge cases:** - **Direction of keys is easy to invert:** you *sign with your private key, verify with their public*; you *encrypt with their public key, decrypt with your private*. Mixing these up is the most common WSS bug. - **Which parts are secured.** By default WSS4J may secure the SOAP Body; if a policy requires signing the Timestamp or specific headers, you must configure `...SignatureParts`/`...EncryptionParts` precisely, or interop fails. - **Sign-then-encrypt vs encrypt-then-sign** changes what a signature covers; policies dictate one. Action order is how you express it. - **Certificate trust & expiry.** Validation fails if the signer cert isn't in the truststore or has expired; keystore rotation is operational overhead. - **Algorithm agility / weak defaults.** Older WSS4J defaults (SHA-1, RSA-1.5) are weak; modern configs pin SHA-256, AES-GCM, RSA-OAEP. - **Performance.** Asymmetric crypto per message is costly; encryption uses a symmetric session key for the bulk to mitigate this, but signing/verifying still adds latency vs plain TLS. - **Keystore passwords vs key passwords** are distinct; the callback handler must return the *key* password for the alias. **When to use.** Message-level signing/encryption is warranted when messages pass through untrusted intermediaries, when non-repudiation is required, when a partner's WS-SecurityPolicy mandates it, or when only *parts* of a message must be confidential. If a simple secure point-to-point channel suffices, TLS (with optional mutual TLS) is far cheaper — many teams reserve WSS sign/encrypt for contractual/regulatory requirements.
- Which key signs and which key encrypts, and why?You sign with your own private key (only you hold it, so verification with your public cert proves authenticity and integrity). You encrypt with the recipient's public key (so only the recipient's private key can decrypt). Inverting these — the classic mistake — breaks both properties.
- Why encrypt the body with a symmetric key rather than directly with the recipient's RSA public key?Asymmetric encryption is slow and size-limited. WSS4J uses hybrid encryption: a fast random symmetric key (e.g. AES-GCM) encrypts the payload, and only that small symmetric key is wrapped with the recipient's RSA public key (RSA-OAEP). This is efficient and handles arbitrarily large bodies.
saying these in an interview costs you the question
- Saying you encrypt with your own private key or sign with the recipient's public key (keys inverted)
- Claiming the whole body is RSA-encrypted directly rather than via a wrapped symmetric key
- Treating signing and encryption as the same guarantee (they cover integrity/authenticity vs confidentiality)
- Ignoring which parts are signed/encrypted, causing policy interop failures
- Assuming TLS makes WS-Security signing redundant when non-repudiation or intermediaries are involved