== Body Encryption and Signing via SMIME

S/MIME (Secure/Multipurpose Internet Mail Extensions) is a standard for public key encryption and signing of MIME data.
MIME data being a set of headers and a message body.
Its most often seen in the email world when somebody wants to encrypt and/or sign an email message they are sending across the internet.
It can also be used for HTTP requests as well which is what the RESTEasy integration with S/MIME is all about.
RESTEasy allows you to easily encrypt and/or sign an email message using the S/MIME standard. 

=== Maven settings

Reference the resteasy-crypto archive to use the smime framework.


[source,xml,subs="attributes+"]
----
<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-crypto</artifactId>
    <version>{resteasy-version}</version>
</dependency>
----

=== Message Body Encryption

While HTTPS is used to encrypt the entire HTTP message, S/MIME encryption is used solely for the message body of the HTTP request or response.
This is very useful if there is a representation that may be forwarded by multiple parties (for example, HornetQ's REST Messaging integration!) and the message needed to be protected from prying eyes as it travels across the network.
RESTEasy has two different interfaces for encrypting message bodies.
One for output, one for input.
If the client or server wants to send an HTTP request or response with an encrypted body, it uses the `org.jboss.resteasy.security.smime.EnvelopedOutput` type.
Encrypting a body also requires an X509 certificate which can be generated by the Java keytool command-line interface, or the openssl tool that comes installed on many OS's.
Here's an example of using the `EnvelopedOutput` interface:

[source,java]
.Server Side
----

@Path("encrypted")
@GET
public EnvelopedOutput getEncrypted(){
   Customer cust = new Customer();
   cust.setName("Bill");
   
   X509Certificate certificate = createCert();
   EnvelopedOutput output = new EnvelopedOutput(cust, MediaType.APPLICATION_XML_TYPE);
   output.setCertificate(certificate);
   return output;
}
----

[source,java]
.Client Side
----
// client side
X509Certificate cert = createCert();
Customer cust = new Customer();
cust.setName("Bill");
EnvelopedOutput output = new EnvelopedOutput(cust, "application/xml");
output.setCertificate(cert);
Response res = target.request().post(Entity.entity(output, "application/pkcs7-mime").post();
----

An EnvelopedOutput instance is created passing in the entity to be marshaled and the media type to marshal into.
In this example, a Customer class is being marshaled into XML before it is encrypted.
RESTEasy will then encrypt the EnvelopedOutput using the BouncyCastle framework's SMIME integration.
The output is a Base64 encoding and would look something like this:

[source]
----
Content-Type: application/pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7m"

MIAGCSqGSIb3DQEHA6CAMIACAQAxgewwgekCAQAwUjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMK
U29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkAgkA7oW81OriflAw
DQYJKoZIhvcNAQEBBQAEgYCfnqPK/O34DFl2p2zm+xZQ6R+94BqZHdtEWQN2evrcgtAng+f2ltIL
xr/PiK+8bE8wDO5GuCg+k92uYp2rLKlZ5BxCGb8tRM4kYC9sHbH2dPaqzUBhMxjgWdMCX6Q7E130
u9MdGcP74Ogwj8fNl3lD4sx/0k02/QwgaukeY7uNHzCABgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcE
CDRozFLsPnSgoIAEQHmqjSKAWlQbuGQL9w4nKw4l+44WgTjKf7mGWZvYY8tOCcdmhDxRSM1Ly682
Imt+LTZf0LXzuFGTsCGOUo742N8AAAAAAAAAAAAA
----

Decrypting an S/MIME encrypted message requires using the org.jboss.resteasy.security.smime.EnvelopedInput interface.
Both the private key and X509Certificate used to encrypt the message are also needed.
Here's an example:

[source,java]
.Server Side
----
@Path("encrypted")
@POST
public void postEncrypted(EnvelopedInput<Customer> input) {
   PrivateKey privateKey = createKey();
   X509Certificate certificate = createCert();
   Customer cust = input.getEntity(privateKey, certificate);
}
----

[source,java]
.Client Side
----
ClientRequest request = new ClientRequest("http://localhost:9095/smime/encrypted");
EnvelopedInput input = request.getTarget(EnvelopedInput.class);
Customer cust = (Customer)input.getEntity(Customer.class, privateKey, cert);
----

Both examples simply call the `getEntity()` method passing in the `PrivateKey` and `X509Certificate` instances requires to decrypt the message.
On the server side, a generic is used with `EnvelopedInput` to specify the type to marshal to.
On the server side this information is passed as a parameter to `getEntity()`. The message is in MIME format: a
Content-Type header and body, so the `EnvelopedInput` class has everything it needs to both decrypt and unmarshall the entity.

=== Message Body Signing

S/MIME allows the user to digitally sign a message.
It is different than the Doseta Digital Signing Framework.
Doseta is an HTTP header that contains the signature.
S/MIME uses the multipart/signed data format which is a multipart message that contains the entity and the digital signature.
Doseta is a header, S/MIME is its own media type.
S/MIME signatures require the client to know how to parse a multipart message and Doseta doesn't.
It is left to the user to select the method to use.

RESTEasy has two different interfaces for creating a multipart/signed message.
One for input, one for output.
If the client or server is to send an HTTP request or response with a multipart/signed body, it uses the `org.jboss.resteasy.security.smime.SignedOutput` type.
This type requires both the PrivateKey and X509Certificate to create the signature.
Here's an example of signing an entity and sending a multipart/signed entity.

[source,java]
.Server Side
----
@Path("signed")
@GET
@Produces("multipart/signed")
public SignedOutput getSigned() {
    Customer cust = new Customer();
    cust.setName("Bill");

    SignedOutput output = new SignedOutput(cust, MediaType.APPLICATION_XML_TYPE);
    output.setPrivateKey(privateKey);
    output.setCertificate(certificate);
    return output;
}
----

[source,java]
.Client Side
----
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:9095/smime/signed");
Customer cust = new Customer();
cust.setName("Bill");
SignedOutput output = new SignedOutput(cust, "application/xml");
output.setPrivateKey(privateKey);
output.setCertificate(cert);
Response res = target.request().post(Entity.entity(output, "multipart/signed");
----

An SignedOutput instance is created passing in the entity wanted to be marshaled and the media type to marshal into.
In this example, a Customer class is marshaled into XML before it is sign.
RESTEasy will then sign the SignedOutput using the BouncyCastle framework's SMIME integration.
The output would look like this:

[source]
----
Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg=sha1;  boundary="----=_Part_0_1083228271.1313024422098"

------=_Part_0_1083228271.1313024422098
Content-Type: application/xml
Content-Transfer-Encoding: 7bit

<customer name="bill"/>
------=_Part_0_1083228271.1313024422098
Content-Type: application/pkcs7-signature; name=smime.p7s; smime-type=signed-data
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
Content-Description: S/MIME Cryptographic Signature

MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAMYIBVzCCAVMC
AQEwUjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJu
ZXQgV2lkZ2l0cyBQdHkgTHRkAgkA7oW81OriflAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzEL
BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTExMDgxMTAxMDAyMlowIwYJKoZIhvcNAQkEMRYE
FH32BfR1l1vzDshtQvJrgvpGvjADMA0GCSqGSIb3DQEBAQUABIGAL3KVi3ul9cPRUMYcGgQmWtsZ
0bLbAldO+okrt8mQ87SrUv2LGkIJbEhGHsOlsgSU80/YumP+Q4lYsVanVfoI8GgQH3Iztp+Rce2c
y42f86ZypE7ueynI4HTPNHfr78EpyKGzWuZHW4yMo70LpXhk5RqfM9a/n4TEa9QuTU76atAAAAAA
AAA=
------=_Part_0_1083228271.1313024422098--
----

To unmarshal and verify a signed message requires using the `org.jboss.resteasy.security.smime.SignedInput` interface.
Only the X509Certificate is needed to verify the message.
Here's an example of unmarshalling and verifying a multipart/signed entity.

[source,java]
.Server Side
----
@Path("signed")
@POST
@Consumes("multipart/signed")
public void postSigned(SignedInput<Customer> input) throws Exception {
    Customer cust = input.getEntity();
    if (!input.verify(certificate)) {
        throw new WebApplicationException(500);
    }
}
----

[source,java]
.Client Side
----
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:9095/smime/signed");
SignedInput input = target.request().get(SignedInput.class);
Customer cust = (Customer)input.getEntity(Customer.class)
input.verify(cert);
----

=== application/pkcs7-signature

application/pkcs7-signature is a data format that includes both the data and the signature in one ASN.1 binary encoding. 

SignedOutput and SignedInput can be used to return application/pkcs7-signature format in binary form.
Just change the @Produces or @Consumes to that media type to send back that format. 

Also, if the @Produces or @Consumes is text/plain instead, SignedOutput will be base64 encoded and sent as a string. 