Kohei Nozaki's blog 

Configuring James to sign DKIM for outbound mails


Posted on Saturday Feb 07, 2015 at 01:20PM in Technology


Environment

  • Apache jDKIM 0.3-SNAPSHOT

  • Apache James 3.0.0-beta5-SNAPSHOT

  • Oracle JDK7u51

Obtaining and building jDKIM

svn co http://svn.apache.org/repos/asf/james/jdkim/trunk jdkim
cd jdkim
mvn clean install

Put jars of jDKIM into James

Put following files packed in $JDKIM_HOME/assemble/target/apache-jdkim-0.3-SNAPSHOT-bin.tar.gz into $JAMES_HOME/conf/lib of your James server:

  1. apache-jdkim-library-0.3-SNAPSHOT.jar

  2. apache-jdkim-mailets-0.3-SNAPSHOT.jar

  3. lib/not-yet-commons-ssl-0.3.11.jar

Creating key pair

openssl genrsa -out dkim-private.pem 1024 -outform PEM
openssl rsa -in dkim-private.pem -out dkim-public.pem -pubout -outform PEM

Registering public key into DNS

20150207._domainkey IN TXT "k=rsa; p=[YOUR PUBLIC KEY HERE EXCLUDE THE HEADER AND FOOTER];"

20150207 is a selector and which identifies the key. it’s recommended to rotate periodically so timestamp manner like YYYYMMDD is reasonable. GMail is used this way too.

Following command is useful if you don’t want to concatenate and strip the header and footer by hand:

awk 'NR>1{a[++k]=$0}END{for(i=1;i<k;i++){printf("%s", a[i])}; printf("\n")}' dkim-public.pem

You can test whether the key is successfully registered as follows:

host -t txt 20150207._domainkey.example.com

Defining Mailets

Put following definition to $JAMES_HOME/conf/mailetcontainer.xml. make sure to put the value of s (selector) that is the same as one which you just have registered in DNS. and you have to replace d (domain) with your domain. note that you should put following definition to place just before <mailet match="All" class="RemoteDelivery"> element to prevent altering mails after signing.

<mailet match="All" class="org.apache.james.jdkim.mailets.ConvertTo7Bit"/>

<mailet match="All" class="org.apache.james.jdkim.mailets.DKIMSign">
  <signatureTemplate>v=1; s=20150207; d=example.com; c=relaxed/relaxed; h=Message-ID:Date:Subject:From:To:MIME-Version:Content-Type; a=rsa-sha256; bh=; b=;</signatureTemplate>
  <privateKey>
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
  </privateKey>
</mailet>

If you have passphrase in your key, you need to put it here as privateKeyPassword argument.

Testing DKIM signature

Go https://www.mail-tester.com and send a mail from your James server.

Invalid signature on Quoted-Printable mails

It works fine with 7bit plain text mails but when I send a long-line mail with Apple Mail which will be converted to Quoted-Printable, James creates invalid signature. I’m investing this problem now but not unsure at present time. maybe investigation in DKIMSign, CRLFOutputStream, RemoteDelivery and SMTPTransport are needed because they have many code of manipulating content.

UPDATE I found the cause. you need to put following definition inside the mailet named RemoteDelivery. JavaMail automatically converts quoted-printable mails to 8bit plain-text mail because RemoteDelivery class sets it to true at its run() method.

<mail.smtp.allow8bitmime>false</mail.smtp.allow8bitmime>


Configuring James to use SSL


Posted on Saturday Feb 07, 2015 at 12:07AM in Technology


Environment

  • Apache James 3.0.0beta5-SNAPSHOT

  • Oracle JDK8u31

  • CentOS 6.5

Requirement

  • Listening IMAPS at 993

  • Listening SMTPS at 465 (for mail client)

  • Listening SMTP at 25 (for accepting connection from other SMTP server. STARTTLS enabled)

  • Expose these ports with forwarding by iptables

Put Java KeyStore

I put it to $JAMES_HOME/conf/mykeystore.jks. check this posting for how to create the Java KeyStore.

Configuring IMAPS

  1. Change port number in bind element as follows:

    <bind>0.0.0.0:10993</bind>
  2. Edit tls element as follows:

    <tls socketTLS="true" startTLS="false">
     <keystore>file://conf/mykeystore.jks</keystore>
     <secret>PASSPHRASE</secret>
     <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
    </tls>

    I guess I don’t have BouncyCastleProvider class in my classpath but it works.

Configuring SMTPS

  1. Make a whole copy of smtpserver element in smtpserver.xml.

  2. Change jmxName element of second smtpserver element:

    <jmxName>smtpsserver</jmxName>
  3. Change port number in bind element as well:

    <bind>0.0.0.0:10465</bind>
  4. Edit tls element too:

    <tls socketTLS="true" startTLS="false">
     <keystore>file://conf/mykeystore.jks</keystore>
     <secret>PASSPHRASE</secret>
     <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
     <algorithm>SunX509</algorithm>
    </tls>
  5. Also enabling of following configuration is required for some mail client such as Apple Mail:

    <authRequired>announce</authRequired>

Configuring SMTP

Edit tls element inside first smtpserver element. set true to startTLS:

<tls socketTLS="false" startTLS="true">
 <keystore>file://conf/mykeystore.jks</keystore>
 <secret>PASSPHRASE</secret>
 <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
 <algorithm>SunX509</algorithm>
</tls>

Delete a Mailet from mailetcontainer.xml

There’s a Mailet which needs to get removed when you use SMTP auth. this solves the problem that getting Storing mail …​ in file://var/mail/relay-denied/. so delete following fragment from $JAMES_HOME/conf/mailetcontainer.xml:

<mailet match="RemoteAddrNotInNetwork=127.0.0.1" class="ToProcessor">
  <processor>relay-denied</processor>
  <notice>550 - Requested action not taken: relaying denied</notice>
</mailet>

In my case, a class named AuthRequiredToRelayRcptHook prevents open relay, without that Mailet.

Configuring iptables

An example as follows. write it to /etc/sysconfig/iptables and issue sudo service iptables restart.

*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination :10025
-A PREROUTING -i eth0 -p tcp --dport 465 -j DNAT --to-destination :10465
-A PREROUTING -i eth0 -p tcp --dport 993 -j DNAT --to-destination :10993
COMMIT
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 10025 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 10465 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 10993 -j ACCEPT
COMMIT

Open relay check of SMTP server

Just in case, do it with testing site like http://www.aupads.org/test-relay.html


Creating Java KeyStore from X.509 certificate


Posted on Friday Feb 06, 2015 at 10:00PM in Technology


Environment

  • Oracle JDK 8u20

  • OpenSSL 0.9.8zc 15 Oct 2014

  • A certificate bought from RapidSSL

Files

  • key.pem: Private key (Created with openssl command as I wrote in previous posting)

  • certificate.txt: Certificate which sent from the seller via email

  • intermediate_ca.txt: Intermediate CA which sent from the seller via email

Create CAFile

curl -O https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt
cat intermediate_ca.txt ca-bundle.crt > allcacerts.crt

Create PKCS12 key store

openssl pkcs12 -export -chain -CAfile allcacerts.crt -in certificate.txt -inkey key.pem -out mykeystore.pkcs12 -name java

Create Java KeyStore

keytool -importkeystore -srckeystore mykeystore.pkcs12 -srcstoretype pkcs12 -srcalias java -destkeystore mykeystore.jks -deststoretype jks -destalias mykey

Show list of entries in key store

keytool -v -list -storetype jks -keystore mykeystore.jks

Now mykeystore.jks is usable for application built upon Java.


Obtaining a SSL certification


Posted on Friday Feb 06, 2015 at 06:43PM in Technology


SSL certification are cheap these days. even there is free one is available. you can obtain personal one for around $10 per one year.

What you need

  • Payment method (PayPal account, a credit card…​ usable method may vary depending on seller)

  • An administrative mail address in the domain which the certification will be issued to (e.g. postmaster@example.org)

Common procedure is following:

Create a random seed

openssl md5 /var/log/*.log* > rand.dat

Create a private key

openssl genrsa -rand rand.dat -des3 2048 > key.pem

Create CSR from private key

openssl req -new -key key.pem -out csr.pem

I entered following:

Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:.
Organizational Unit Name (eg, section) []:.
Common Name (e.g. server FQDN or YOUR name) []:www.nailedtothex.org
Email Address []:postmaster@MYDOMAIN.example.org

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Send CSR to certification authority (SSL certification seller)

The seller will send you the certification. now you need to apply certification to your servers (HTTP, SMTP, IMAP…​ etc).


Configuring helo names of James


Posted on Friday Feb 06, 2015 at 04:47PM in Technology


My James instance looks like failed to determine its hostname as follows:

$ telnet localhost 10025
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 localhost.localdomain JAMES SMTP Server Server (JAMES SMTP Server ) ready
helo example.com
250 localhost.localdomain Hello example.com [127.0.0.1])

This can be solved by editing XML files such as smtpserver.xml, pop3server.xml and imapserver.xml respectively as follows:

<helloName autodetect="false">www.nailedtothex.org</helloName>

Also you should check that the name which James will use during communicate to another SMTP server. you can check it easily with this site. if the name is wrong, this may be a cause of that remote server will consider your James server as spammer. the name to use will be hostname of the server. you can check it with simply issuing hostname command on Linux.

Unfortunately you can’t set the hostname in portable way due to a bug in a dependency geronimo-javamail_1.4_mail. the hostname should be able to configured in mailetcontainer.xml as follows but not worked at the present time.

<!-- Set the HELO/EHLO name to use when connectiong to remote SMTP-Server -->
<mail.smtp.localhost>www.nailedtothex.org</mail.smtp.localhost>

So current geronimo-javamail_1.4_mail ignores that value. considerable solutions are following:

  1. Change the hostname of the server (for <= Java 7u51)

  2. Put you FQDN first (before localhost) in /etc/hosts. detail (for recent Java)

  3. Apply a patch to James

  4. Apply a patch to Geronimo JavaMail and update dependency of James. unfortunately seems like that fixed version of Geronimo JavaMail is not released yet.