import javax.servlet.http.HttpSession;
import org.cacert.gigi.database.DatabaseConnection;
-import org.cacert.gigi.email.EmailProvider;
import org.cacert.gigi.localisation.Language;
import org.cacert.gigi.output.Form.CSRFException;
import org.cacert.gigi.output.Menu;
Menu m;
public Gigi(Properties conf) {
- EmailProvider.init(conf);
DatabaseConnection.init(conf);
}
import java.io.IOException;
import java.security.GeneralSecurityException;
+import java.security.Key;
import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
import java.util.List;
import java.util.Properties;
import javax.net.ssl.SSLSession;
import org.cacert.gigi.api.GigiAPI;
+import org.cacert.gigi.email.EmailProvider;
import org.cacert.gigi.natives.SetUID;
import org.cacert.gigi.util.CipherInfo;
import org.cacert.gigi.util.ServerConstants;
public static void main(String[] args) throws Exception {
GigiConfig conf = GigiConfig.parse(System.in);
ServerConstants.init(conf.getMainProps());
+ initEmails(conf);
Server s = new Server();
// === SSL HTTP Configuration ===
}
}
+ private static void initEmails(GigiConfig conf) throws GeneralSecurityException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+ KeyStore privateStore = conf.getPrivateStore();
+ Certificate mail = privateStore.getCertificate("mail");
+ Key k = privateStore.getKey("mail", conf.getPrivateStorePw().toCharArray());
+ EmailProvider.initSystem(conf.getMainProps(), mail, k);
+ }
+
private static SslConnectionFactory createConnectionFactory(GigiConfig conf) throws GeneralSecurityException, IOException {
final SslContextFactory sslContextFactory = generateSSLContextFactory(conf, "www");
final SslContextFactory secureContextFactory = generateSSLContextFactory(conf, "secure");
--- /dev/null
+package org.cacert.gigi.crypto;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+import java.util.Random;
+
+import sun.security.pkcs.ContentInfo;
+import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.SignerInfo;
+import sun.security.util.DerOutputStream;
+import sun.security.x509.AlgorithmId;
+import sun.security.x509.X500Name;
+
+public class SMIME {
+
+ public static String doAlternatives(String plain, String html) {
+
+ plain = "Content-type: text/plain\r\n\r\n" + plain;
+ html = "Content-type: text/html\r\n\r\n" + html;
+ String boundary = generateBoundary(plain, html);
+ StringBuffer content = new StringBuffer("Content-Type: multipart/alternative; boundary=\"");
+ content.append(boundary);
+ content.append("\"\r\n\r\n");
+ content.append("--");
+ content.append(boundary);
+ content.append("\r\n");
+ content.append(plain);
+ content.append("\r\n--");
+ content.append(boundary);
+ content.append("\r\n");
+ content.append(html);
+ content.append("\r\n--");
+ content.append(boundary);
+ content.append("--\r\n");
+ return content.toString();
+
+ }
+
+ public static void smime(String contents, PrivateKey pKey, X509Certificate c, PrintWriter to) throws IOException, GeneralSecurityException {
+
+ Signature signature = Signature.getInstance("SHA1WithRSA");
+ signature.initSign(pKey);
+ signature.update(contents.getBytes("UTF-8"));
+ byte[] signedData = signature.sign();
+
+ // "IssuerAndSerialNumber"
+ X500Name xName = X500Name.asX500Name(c.getIssuerX500Principal());
+ BigInteger serial = c.getSerialNumber();
+
+ SignerInfo sInfo = new SignerInfo(xName, serial, new AlgorithmId(AlgorithmId.SHA_oid), null, new AlgorithmId(AlgorithmId.RSAEncryption_oid), signedData, null);
+
+ // Content is outside so content here is null.
+ ContentInfo cInfo = new ContentInfo(ContentInfo.DATA_OID, null);
+
+ // Create PKCS7 Signed data
+ PKCS7 p7 = new PKCS7(new AlgorithmId[] {
+ new AlgorithmId(AlgorithmId.SHA_oid)
+ }, cInfo, new java.security.cert.X509Certificate[] {
+ c
+ }, new SignerInfo[] {
+ sInfo
+ });
+
+ ByteArrayOutputStream bOut = new DerOutputStream();
+ p7.encodeSignedData(bOut);
+
+ mimeEncode(contents, Base64.getEncoder().encodeToString(bOut.toByteArray()).replaceAll("(.{64})(?=.)", "$1\n"), to);
+ }
+
+ static Random r = new Random();
+
+ private static void mimeEncode(String contents, String signature, PrintWriter to) {
+ String boundary = generateBoundary(contents, null);
+ to.println("MIME-Version: 1.0");
+ to.println("Content-Type: multipart/signed; protocol=\"application/x-pkcs7-signature\"; micalg=\"sha1\"; boundary=\"" + boundary + "\"");
+ to.println("");
+ to.println("This is an S/MIME signed message");
+ to.println("");
+ to.println("--" + boundary);
+ to.println(contents);
+ to.println("--" + boundary);
+ to.println("Content-Type: application/x-pkcs7-signature; name=\"smime.p7s\"");
+ to.println("Content-Transfer-Encoding: base64");
+ to.println("Content-Disposition: attachment; filename=\"smime.p7s\"");
+ to.println("");
+ to.println(signature);
+ to.println();
+ to.println("--" + boundary + "--");
+ }
+
+ private static String generateBoundary(String contents, String contents2) {
+ String boundary = "";
+ while (contents.contains(boundary) || (contents2 != null && contents2.contains(boundary))) {
+ boundary = "--" + new BigInteger(16 * 8, r).toString(16).toUpperCase();
+ }
+ return boundary;
+ }
+}
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.regex.Pattern;
+import org.cacert.gigi.crypto.SMIME;
import org.cacert.gigi.database.DatabaseConnection;
public abstract class EmailProvider {
private static EmailProvider instance;
+ private X509Certificate c;
+
+ private PrivateKey k;
+
+ protected final void init(Certificate c, Key k) {
+ this.c = (X509Certificate) c;
+ this.k = (PrivateKey) k;
+ }
+
+ protected final void sendSigned(String contents, PrintWriter output) throws IOException, GeneralSecurityException {
+ SMIME.smime(contents, k, c, output);
+ }
+
public static EmailProvider getInstance() {
return instance;
}
EmailProvider.instance = instance;
}
- public static void init(Properties conf) {
+ public static void initSystem(Properties conf, Certificate cert, Key pk) {
try {
Class<?> c = Class.forName(conf.getProperty("emailProvider"));
- instance = (EmailProvider) c.getDeclaredConstructor(Properties.class).newInstance(conf);
+ EmailProvider ep = (EmailProvider) c.getDeclaredConstructor(Properties.class).newInstance(conf);
+ ep.init(cert, pk);
+ instance = ep;
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
+import java.security.GeneralSecurityException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Properties;
import java.util.regex.Pattern;
+import org.cacert.gigi.util.ServerConstants;
+
public class Sendmail extends EmailProvider {
protected Sendmail(Properties props) {}
String[] bits = from.split(",");
- Socket smtp = new Socket("dogcraft.de", 25);
+ Socket smtp = new Socket("localhost", 25);
PrintWriter out = new PrintWriter(smtp.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(smtp.getInputStream()));
readResponse(in);
} else {
out.print("Reply-To: " + from + "\r\n");
}
- out.print("From: " + from + "\r\n");
+ out.print("From: support@" + ServerConstants.getWwwHostName().replaceAll("^www.", "") + "\r\n");
out.print("To: " + to + "\r\n");
if (NON_ASCII.matcher(subject).matches()) {
} else {
out.print("Subject: " + subject + "\r\n");
}
- out.print("Mime-Version: 1.0\r\n");
- if ( !extra) {
- out.print("Content-Type: text/plain; charset=\"utf-8\"\r\n");
- out.print("Content-Transfer-Encoding: 8bit\r\n");
- } else {
- out.print("Content-Type: text/plain; charset=\"iso-8859-1\"\r\n");
- out.print("Content-Transfer-Encoding: quoted-printable\r\n");
- out.print("Content-Disposition: inline\r\n");
- }
- // out.print("Content-Transfer-Encoding: BASE64\r\n");
- out.print("\r\n");
+ StringBuffer headers = new StringBuffer();
+ headers.append("Content-Type: text/plain; charset=\"utf-8\"\r\n");
+ headers.append("Content-Transfer-Encoding: base64\r\n");
// out.print(chunk_split(base64_encode(recode("html..utf-8",
// $message)))."\r\n.\r\n");
- message = message + "\r\n";
+ headers.append("\r\n");
+ headers.append(Base64.getEncoder().encodeToString(message.getBytes("UTF-8")).replaceAll("(.{64})(?=.)", "$1\r\n"));
+ headers.append("\r\n");
- String sendM = message.replace("\r", "").replace("\n.\n", "\n").replace("\n.\n", "\n").replace("\n", "\r\n") + ".\r\n";
- out.print(sendM);
- out.flush();
+ try {
+ sendSigned(headers.toString(), out);
+ out.print("\r\n.\r\n");
+ out.flush();
+ } catch (GeneralSecurityException e) {
+ e.printStackTrace();
+ smtp.close();
+ return;
+ }
readResponse(in);
out.print("QUIT\n");
out.flush();