1 package org.bouncycastle.mail.smime.examples;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.math.BigInteger;
7 import java.security.GeneralSecurityException;
8 import java.security.KeyPair;
9 import java.security.KeyPairGenerator;
10 import java.security.PrivateKey;
11 import java.security.PublicKey;
12 import java.security.SecureRandom;
13 import java.security.cert.CertStore;
14 import java.security.cert.CollectionCertStoreParameters;
15 import java.security.cert.X509Certificate;
16 import java.util.ArrayList;
17 import java.util.Date;
18 import java.util.List;
19 import java.util.Properties;
20
21 import javax.mail.Address;
22 import javax.mail.Message;
23 import javax.mail.Session;
24 import javax.mail.internet.InternetAddress;
25 import javax.mail.internet.MimeBodyPart;
26 import javax.mail.internet.MimeMessage;
27 import javax.mail.internet.MimeMultipart;
28
29 import org.bouncycastle.asn1.ASN1EncodableVector;
30 import org.bouncycastle.asn1.ASN1InputStream;
31 import org.bouncycastle.asn1.ASN1Sequence;
32 import org.bouncycastle.asn1.cms.AttributeTable;
33 import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
34 import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute;
35 import org.bouncycastle.asn1.smime.SMIMECapability;
36 import org.bouncycastle.asn1.smime.SMIMECapabilityVector;
37 import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute;
38 import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
39 import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
40 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
41 import org.bouncycastle.asn1.x509.X509Extensions;
42 import org.bouncycastle.asn1.x509.X509Name;
43 import org.bouncycastle.x509.X509V3CertificateGenerator;
44 import org.bouncycastle.mail.smime.SMIMESignedGenerator;
45
46 /**
47 * a simple example that creates a single signed mail message.
48 */
49 public class CreateSignedMail
50 {
51 //
52 // certificate serial number seed.
53 //
54 static int serialNo = 1;
55
56 static AuthorityKeyIdentifier createAuthorityKeyId(
57 PublicKey pub)
58 throws IOException
59 {
60 ByteArrayInputStream bIn = new ByteArrayInputStream(pub.getEncoded());
61 SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
62 (ASN1Sequence)new ASN1InputStream(bIn).readObject());
63
64 return new AuthorityKeyIdentifier(info);
65 }
66
67 static SubjectKeyIdentifier createSubjectKeyId(
68 PublicKey pub)
69 throws IOException
70 {
71 ByteArrayInputStream bIn = new ByteArrayInputStream(pub.getEncoded());
72
73 SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
74 (ASN1Sequence)new ASN1InputStream(bIn).readObject());
75
76 return new SubjectKeyIdentifier(info);
77 }
78
79 /**
80 * create a basic X509 certificate from the given keys
81 */
82 static X509Certificate makeCertificate(
83 KeyPair subKP,
84 String subDN,
85 KeyPair issKP,
86 String issDN)
87 throws GeneralSecurityException, IOException
88 {
89 X509Name xName = new X509Name(subDN);
90 PublicKey subPub = subKP.getPublic();
91 PrivateKey issPriv = issKP.getPrivate();
92 PublicKey issPub = issKP.getPublic();
93
94 X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
95
96 v3CertGen.setSerialNumber(BigInteger.valueOf(serialNo++));
97 v3CertGen.setIssuerDN(new X509Name(issDN));
98 v3CertGen.setNotBefore(new Date(System.currentTimeMillis()));
99 v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)));
100 v3CertGen.setSubjectDN(new X509Name(subDN));
101 v3CertGen.setPublicKey(subPub);
102 v3CertGen.setSignatureAlgorithm("MD5WithRSAEncryption");
103
104 v3CertGen.addExtension(
105 X509Extensions.SubjectKeyIdentifier,
106 false,
107 createSubjectKeyId(subPub));
108
109 v3CertGen.addExtension(
110 X509Extensions.AuthorityKeyIdentifier,
111 false,
112 createAuthorityKeyId(issPub));
113
114 return v3CertGen.generateX509Certificate(issPriv);
115 }
116
117 public static void main(
118 String args[])
119 throws Exception
120 {
121 //
122 // set up our certs
123 //
124 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
125
126 kpg.initialize(1024, new SecureRandom());
127
128 //
129 // cert that issued the signing certificate
130 //
131 String signDN = "O=Bouncy Castle, C=AU";
132 KeyPair signKP = kpg.generateKeyPair();
133 X509Certificate signCert = makeCertificate(
134 signKP, signDN, signKP, signDN);
135
136 //
137 // cert we sign against
138 //
139 String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
140 KeyPair origKP = kpg.generateKeyPair();
141 X509Certificate origCert = makeCertificate(
142 origKP, origDN, signKP, signDN);
143
144 List certList = new ArrayList();
145
146 certList.add(origCert);
147 certList.add(signCert);
148
149 //
150 // create a CertStore containing the certificates we want carried
151 // in the signature
152 //
153 CertStore certsAndcrls = CertStore.getInstance(
154 "Collection",
155 new CollectionCertStoreParameters(certList), "BC");
156
157 //
158 // create some smime capabilities in case someone wants to respond
159 //
160 ASN1EncodableVector signedAttrs = new ASN1EncodableVector();
161 SMIMECapabilityVector caps = new SMIMECapabilityVector();
162
163 caps.addCapability(SMIMECapability.dES_EDE3_CBC);
164 caps.addCapability(SMIMECapability.rC2_CBC, 128);
165 caps.addCapability(SMIMECapability.dES_CBC);
166
167 signedAttrs.add(new SMIMECapabilitiesAttribute(caps));
168
169 //
170 // add an encryption key preference for encrypted responses -
171 // normally this would be different from the signing certificate...
172 //
173 IssuerAndSerialNumber issAndSer = new IssuerAndSerialNumber(
174 new X509Name(signDN), origCert.getSerialNumber());
175
176 signedAttrs.add(new SMIMEEncryptionKeyPreferenceAttribute(issAndSer));
177
178 //
179 // create the generator for creating an smime/signed message
180 //
181 SMIMESignedGenerator gen = new SMIMESignedGenerator();
182
183 //
184 // add a signer to the generator - this specifies we are using SHA1 and
185 // adding the smime attributes above to the signed attributes that
186 // will be generated as part of the signature. The encryption algorithm
187 // used is taken from the key - in this RSA with PKCS1Padding
188 //
189 gen.addSigner(origKP.getPrivate(), origCert, SMIMESignedGenerator.DIGEST_SHA1, new AttributeTable(signedAttrs), null);
190
191 //
192 // add our pool of certs and cerls (if any) to go with the signature
193 //
194 gen.addCertificatesAndCRLs(certsAndcrls);
195
196 //
197 // create the base for our message
198 //
199 MimeBodyPart msg = new MimeBodyPart();
200
201 msg.setText("Hello world!");
202
203 //
204 // extract the multipart object from the SMIMESigned object.
205 //
206 MimeMultipart mm = gen.generate(msg, "BC");
207
208 //
209 // Get a Session object and create the mail message
210 //
211 Properties props = System.getProperties();
212 Session session = Session.getDefaultInstance(props, null);
213
214 Address fromUser = new InternetAddress("\"Eric H. Echidna\"<eric@bouncycastle.org>");
215 Address toUser = new InternetAddress("example@bouncycastle.org");
216
217 MimeMessage body = new MimeMessage(session);
218 body.setFrom(fromUser);
219 body.setRecipient(Message.RecipientType.TO, toUser);
220 body.setSubject("example signed message");
221 body.setContent(mm, mm.getContentType());
222 body.saveChanges();
223
224 body.writeTo(new FileOutputStream("signed.message"));
225 }
226 }