Skip to content

Commit

Permalink
add smime example
Browse files Browse the repository at this point in the history
  • Loading branch information
liweinan committed May 11, 2015
1 parent cfe432b commit e6e1b99
Show file tree
Hide file tree
Showing 17 changed files with 697 additions and 0 deletions.
2 changes: 2 additions & 0 deletions pom.xml
Expand Up @@ -9,6 +9,7 @@
<properties>
<dep.junit.version>4.8.2</dep.junit.version>
<dep.resteasy.version>3.0.10.Final</dep.resteasy.version>
<dep.javax.mail.version>1.5.0-b01</dep.javax.mail.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -42,5 +43,6 @@
<modules>
<module>no-dns</module>
<module>use-dns</module>
<module>smime</module>
</modules>
</project>
Binary file added smime/.DS_Store
Binary file not shown.
38 changes: 38 additions & 0 deletions smime/README.md
@@ -0,0 +1,38 @@
SMIME and Resteasy
========================
This example shows how to use SMIME over HTTP to encrypt and/or sign message bodies. The examples use keys and certificates
generated by the 'openssl' command-line utility that is available on most unix-based systems as well as installable
on Windows. If you're doing pure Java, then its fine to use the Java keytool and KeyStore facilities to manage your keys/certificates.
The example also has python clients to show how different languages interacting. This is why we chose to use openssl
to generate our keys/certificates.

The pem files private.pem and cert.pem were generated with this command:

$ openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout private.pem -out cert.pem


There are two ways to run the example:

$ mvn install

This builds, runs the WAR, and then invokes all the Java tests. This basically shows Java to Java communication
passing back and forth SMIME messages over HTTP


The second way is to run the WAR and interact with Python clients:

1. mvn jetty:run

This starts the web server in interaction mode


2. Run one of the python clients

$ python getEncrypted.py
$ python getSigned.py
$ python postEncrypted.py
$ python postSigned.py
$ python getEncryptedSigned.py



29 changes: 29 additions & 0 deletions smime/getEncrypted.py
@@ -0,0 +1,29 @@
import httplib, urlparse
from M2Crypto import BIO, SMIME, X509

conn = httplib.HTTPConnection("localhost:9095")
conn.request("GET", "/smime/encrypted")
res = conn.getresponse()
if res.status != 200:
print res.status
raise Exception("Failed to connect")

contentType = res.getheader("content-type")
data = res.read()

# Need to reconstruct a Mail message with content type
# as SMIME wants it in that format
bio = BIO.MemoryBuffer("Content-Type: ")
bio.write(contentType)
bio.write("\r\n\r\n")
bio.write(data)

s = SMIME.SMIME()
s.load_key('src/main/resources/private.pem', 'src/main/resources/cert.pem')

p7, d = SMIME.smime_load_pkcs7_bio(bio)
out = s.decrypt(p7)

print "--- Received Data ---"
# It may contain headers like Content-Type, so you'll have to parse it
print out
48 changes: 48 additions & 0 deletions smime/getEncryptedSigned.py
@@ -0,0 +1,48 @@
import httplib, urlparse
from M2Crypto import BIO, SMIME, X509

conn = httplib.HTTPConnection("localhost:9095")
conn.request("GET", "/smime/encrypted/signed")
res = conn.getresponse()
if res.status != 200:
print res.status
raise Exception("Failed to connect")

contentType = res.getheader("content-type")
data = res.read()

# Need to reconstruct a Mail message with content type
# as SMIME wants it in that format
bio = BIO.MemoryBuffer("Content-Type: ")
bio.write(contentType)
bio.write("\r\n\r\n")
bio.write(data)

s = SMIME.SMIME()
s.load_key('src/main/resources/private.pem', 'src/main/resources/cert.pem')

p7, d = SMIME.smime_load_pkcs7_bio(bio)
out = s.decrypt(p7)



# Load the signer's cert.
x509 = X509.load_cert('src/main/resources/cert.pem')
sk = X509.X509_Stack()
sk.push(x509)
s.set_x509_stack(sk)

# Load the signer's CA cert. In this case, because the signer's
# cert is self-signed, it is the signer's cert itself.
st = X509.X509_Store()
st.load_info('src/main/resources/cert.pem')
s.set_x509_store(st)

# Recall 'out' contains a PKCS #7 blob.
# Transform 'out'; verify the resulting PKCS #7 blob.
p7_bio = BIO.MemoryBuffer(out)
p7, data = SMIME.smime_load_pkcs7_bio(p7_bio)
v = s.verify(p7, data)

print v

38 changes: 38 additions & 0 deletions smime/getSigned.py
@@ -0,0 +1,38 @@
import httplib, urlparse
from M2Crypto import BIO, SMIME, X509

conn = httplib.HTTPConnection("localhost:9095")
conn.request("GET", "/smime/signed")
res = conn.getresponse()
if res.status != 200:
print res.status
raise Exception("Failed to connect")

contentType = res.getheader("content-type")
data = res.read()

# Need to reconstruct a Mail message with content type
# as SMIME wants it in that format
bio = BIO.MemoryBuffer("Content-Type: ")
bio.write(contentType)
bio.write("\r\n\r\n")
bio.write(data)

s = SMIME.SMIME()

# Load the signer's cert.
x509 = X509.load_cert('src/main/resources/cert.pem')
sk = X509.X509_Stack()
sk.push(x509)
s.set_x509_stack(sk)

# Load the signer's CA cert. In this case, because the signer's
# cert is self-signed, it is the signer's cert itself.
st = X509.X509_Store()
st.load_info('src/main/resources/cert.pem')
s.set_x509_store(st)

# Load the data, verify it.
p7, data = SMIME.smime_load_pkcs7_bio(bio)
v = s.verify(p7, data)
print v
90 changes: 90 additions & 0 deletions smime/pom.xml
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jboss.resteasy</groupId>
<artifactId>digital-signatures</artifactId>
<version>3.0.10.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jboss.resteasy.test</groupId>
<artifactId>smime-example</artifactId>
<packaging>war</packaging>
<name>smime-example</name>
<description/>
<url>http://maven.apache.org</url>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${dep.junit.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${dep.resteasy.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${dep.resteasy.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-crypto</artifactId>
<version>${dep.resteasy.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>${dep.resteasy.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<finalName>smime</finalName>
<plugins>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>1.1.0.Alpha1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>surefire-it</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>false</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
62 changes: 62 additions & 0 deletions smime/postEncrypted.py
@@ -0,0 +1,62 @@
import httplib, urlparse
from M2Crypto import BIO, Rand, SMIME, X509

# Make a MemoryBuffer of the message.
buf = BIO.MemoryBuffer(
"""Content-Type: application/xml
<customer name="bill"/>
""")

# Seed the PRNG.
Rand.load_file('randpool.dat', -1)

# Instantiate an SMIME object.
s = SMIME.SMIME()

# Load target cert to encrypt to.
x509 = X509.load_cert('src/main/resources/cert.pem')
sk = X509.X509_Stack()
sk.push(x509)
s.set_x509_stack(sk)

# Set cipher: 3-key triple-DES in CBC mode.
s.set_cipher(SMIME.Cipher('des_ede3_cbc'))

# Encrypt the buffer.
p7 = s.encrypt(buf)

out = BIO.MemoryBuffer()
s.write(out, p7)

# Strip out junk, I can't figure out a better way to do this
# This is kind of a hack, but I couldn't figure out how to just
# get the body without the headers, or just send the BIO directly thru the HTTP connection
# s.write(out, py) adds a bunch of headers and doesn't just output the body
# so, I read 5 lines then use the rest of the buffer to initalize the string

out.readline()
out.readline()
out.readline()
out.readline()
out.readline()
o = out.read()

# This is an alternative way to extract the body
#p7.write(out)
#o = out.read()
#o = o.replace('-----BEGIN PKCS7-----', '')
#o = o.replace('-----END PKCS7-----', '')
#o = o.strip()

# Finally send the message
conn = httplib.HTTPConnection("localhost:9095")
headers = {"Content-Disposition" : "attachment; filename=\"smime.p7m\"",
"Content-Type" : "application/pkcs7-mime; smime-type=enveloped-data; name=\"smime.p7m\"",
"Content-Transfer-Encoding" :"base64"}


conn.request("POST", "/smime/encrypted", o, headers)
res = conn.getresponse()
print res.status, res.reason

49 changes: 49 additions & 0 deletions smime/postSigned.py
@@ -0,0 +1,49 @@
import httplib, urlparse
import re
from M2Crypto import BIO, Rand, SMIME, X509


data = """Content-Type: application/xml
<customer name="bill"/>
"""
# Make a MemoryBuffer of the message.


buf = BIO.MemoryBuffer(data)

# Seed the PRNG.
Rand.load_file('randpool.dat', -1)

# Instantiate an SMIME object.
s = SMIME.SMIME()
s.load_key('src/main/resources/private.pem', 'src/main/resources/cert.pem')
p7 = s.sign(buf, SMIME.PKCS7_DETACHED)

out = BIO.MemoryBuffer()
buf = BIO.MemoryBuffer(data)
s.write(out, p7, buf)

# Extract the content-type and multipart message. I can't figure out a better way to do this
# This is kind of a hack, but I couldn't figure out how to just
# get the body and headers separately or just send the BIO directly thru the HTTP connection
l = out.readline()
l = out.readline()

result = re.match('Content-Type: (.*)', l)
contentType = result.group(1)

l = out.readline()
l = out.readline()

o = out.read()

# Finally send the message
conn = httplib.HTTPConnection("localhost:9095")
headers = {"Content-Type" : contentType}


conn.request("POST", "/smime/signed", o, headers)
res = conn.getresponse()
print res.status, res.reason

0 comments on commit e6e1b99

Please sign in to comment.