001: package org.bouncycastle.mail.smime.examples;
002:
003: import java.io.ByteArrayInputStream;
004: import java.io.FileOutputStream;
005: import java.io.IOException;
006: import java.math.BigInteger;
007: import java.security.GeneralSecurityException;
008: import java.security.KeyPair;
009: import java.security.KeyPairGenerator;
010: import java.security.PrivateKey;
011: import java.security.PublicKey;
012: import java.security.SecureRandom;
013: import java.security.cert.CertStore;
014: import java.security.cert.CollectionCertStoreParameters;
015: import java.security.cert.X509Certificate;
016: import java.util.ArrayList;
017: import java.util.Date;
018: import java.util.List;
019: import java.util.Properties;
020:
021: import javax.mail.Address;
022: import javax.mail.Message;
023: import javax.mail.Session;
024: import javax.mail.internet.InternetAddress;
025: import javax.mail.internet.MimeBodyPart;
026: import javax.mail.internet.MimeMessage;
027: import javax.mail.internet.MimeMultipart;
028:
029: import org.bouncycastle.asn1.ASN1EncodableVector;
030: import org.bouncycastle.asn1.ASN1InputStream;
031: import org.bouncycastle.asn1.ASN1Sequence;
032: import org.bouncycastle.asn1.cms.AttributeTable;
033: import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
034: import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute;
035: import org.bouncycastle.asn1.smime.SMIMECapability;
036: import org.bouncycastle.asn1.smime.SMIMECapabilityVector;
037: import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute;
038: import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
039: import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
040: import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
041: import org.bouncycastle.asn1.x509.X509Extensions;
042: import org.bouncycastle.asn1.x509.X509Name;
043: import org.bouncycastle.x509.X509V3CertificateGenerator;
044: import org.bouncycastle.mail.smime.SMIMESignedGenerator;
045:
046: /**
047: * a simple example that creates a single signed multipart mail message.
048: */
049: public class CreateSignedMultipartMail {
050: //
051: // certificate serial number seed.
052: //
053: static int serialNo = 1;
054:
055: static AuthorityKeyIdentifier createAuthorityKeyId(PublicKey pub)
056: throws IOException {
057: ByteArrayInputStream bIn = new ByteArrayInputStream(pub
058: .getEncoded());
059: SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
060: (ASN1Sequence) new ASN1InputStream(bIn).readObject());
061:
062: return new AuthorityKeyIdentifier(info);
063: }
064:
065: static SubjectKeyIdentifier createSubjectKeyId(PublicKey pub)
066: throws IOException {
067: ByteArrayInputStream bIn = new ByteArrayInputStream(pub
068: .getEncoded());
069:
070: SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
071: (ASN1Sequence) new ASN1InputStream(bIn).readObject());
072:
073: return new SubjectKeyIdentifier(info);
074: }
075:
076: /**
077: * create a basic X509 certificate from the given keys
078: */
079: static X509Certificate makeCertificate(KeyPair subKP, String subDN,
080: KeyPair issKP, String issDN)
081: throws GeneralSecurityException, IOException {
082: X509Name xName = new X509Name(subDN);
083: PublicKey subPub = subKP.getPublic();
084: PrivateKey issPriv = issKP.getPrivate();
085: PublicKey issPub = issKP.getPublic();
086:
087: X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
088:
089: v3CertGen.setSerialNumber(BigInteger.valueOf(serialNo++));
090: v3CertGen.setIssuerDN(new X509Name(issDN));
091: v3CertGen.setNotBefore(new Date(System.currentTimeMillis()));
092: v3CertGen.setNotAfter(new Date(System.currentTimeMillis()
093: + (1000L * 60 * 60 * 24 * 100)));
094: v3CertGen.setSubjectDN(new X509Name(subDN));
095: v3CertGen.setPublicKey(subPub);
096: v3CertGen.setSignatureAlgorithm("MD5WithRSAEncryption");
097:
098: v3CertGen.addExtension(X509Extensions.SubjectKeyIdentifier,
099: false, createSubjectKeyId(subPub));
100:
101: v3CertGen.addExtension(X509Extensions.AuthorityKeyIdentifier,
102: false, createAuthorityKeyId(issPub));
103:
104: return v3CertGen.generateX509Certificate(issPriv);
105: }
106:
107: public static void main(String args[]) throws Exception {
108: //
109: // set up our certs
110: //
111: KeyPairGenerator kpg = KeyPairGenerator
112: .getInstance("RSA", "BC");
113:
114: kpg.initialize(1024, new SecureRandom());
115:
116: //
117: // cert that issued the signing certificate
118: //
119: String signDN = "O=Bouncy Castle, C=AU";
120: KeyPair signKP = kpg.generateKeyPair();
121: X509Certificate signCert = makeCertificate(signKP, signDN,
122: signKP, signDN);
123:
124: //
125: // cert we sign against
126: //
127: String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
128: KeyPair origKP = kpg.generateKeyPair();
129: X509Certificate origCert = makeCertificate(origKP, origDN,
130: signKP, signDN);
131:
132: List certList = new ArrayList();
133:
134: certList.add(origCert);
135: certList.add(signCert);
136:
137: //
138: // create a CertStore containing the certificates we want carried
139: // in the signature
140: //
141: CertStore certsAndcrls = CertStore.getInstance("Collection",
142: new CollectionCertStoreParameters(certList), "BC");
143:
144: //
145: // create some smime capabilities in case someone wants to respond
146: //
147: ASN1EncodableVector signedAttrs = new ASN1EncodableVector();
148: SMIMECapabilityVector caps = new SMIMECapabilityVector();
149:
150: caps.addCapability(SMIMECapability.dES_EDE3_CBC);
151: caps.addCapability(SMIMECapability.rC2_CBC, 128);
152: caps.addCapability(SMIMECapability.dES_CBC);
153:
154: signedAttrs.add(new SMIMECapabilitiesAttribute(caps));
155:
156: //
157: // add an encryption key preference for encrypted responses -
158: // normally this would be different from the signing certificate...
159: //
160: IssuerAndSerialNumber issAndSer = new IssuerAndSerialNumber(
161: new X509Name(signDN), origCert.getSerialNumber());
162:
163: signedAttrs.add(new SMIMEEncryptionKeyPreferenceAttribute(
164: issAndSer));
165:
166: //
167: // create the generator for creating an smime/signed message
168: //
169: SMIMESignedGenerator gen = new SMIMESignedGenerator();
170:
171: //
172: // add a signer to the generator - this specifies we are using SHA1 and
173: // adding the smime attributes above to the signed attributes that
174: // will be generated as part of the signature. The encryption algorithm
175: // used is taken from the key - in this RSA with PKCS1Padding
176: //
177: gen.addSigner(origKP.getPrivate(), origCert,
178: SMIMESignedGenerator.DIGEST_SHA1, new AttributeTable(
179: signedAttrs), null);
180:
181: //
182: // add our pool of certs and cerls (if any) to go with the signature
183: //
184: gen.addCertificatesAndCRLs(certsAndcrls);
185:
186: //
187: // create the base for our message
188: //
189: MimeBodyPart msg1 = new MimeBodyPart();
190:
191: msg1.setText("Hello part 1!");
192:
193: MimeBodyPart msg2 = new MimeBodyPart();
194:
195: msg2.setText("Hello part 2!");
196:
197: MimeMultipart mp = new MimeMultipart();
198:
199: mp.addBodyPart(msg1);
200: mp.addBodyPart(msg2);
201:
202: MimeBodyPart m = new MimeBodyPart();
203:
204: //
205: // be careful about setting extra headers here. Some mail clients
206: // ignore the To and From fields (for example) in the body part
207: // that contains the multipart. The result of this will be that the
208: // signature fails to verify... Outlook Express is an example of
209: // a client that exhibits this behaviour.
210: //
211: m.setContent(mp);
212:
213: //
214: // extract the multipart object from the SMIMESigned object.
215: //
216: MimeMultipart mm = gen.generate(m, "BC");
217:
218: //
219: // Get a Session object and create the mail message
220: //
221: Properties props = System.getProperties();
222: Session session = Session.getDefaultInstance(props, null);
223:
224: Address fromUser = new InternetAddress(
225: "\"Eric H. Echidna\"<eric@bouncycastle.org>");
226: Address toUser = new InternetAddress("example@bouncycastle.org");
227:
228: MimeMessage body = new MimeMessage(session);
229: body.setFrom(fromUser);
230: body.setRecipient(Message.RecipientType.TO, toUser);
231: body.setSubject("example signed message");
232: body.setContent(mm, mm.getContentType());
233: body.saveChanges();
234:
235: body.writeTo(new FileOutputStream("signed.message"));
236: }
237: }
|