Source Code Cross Referenced for SignedMailValidator.java in  » Security » Bouncy-Castle » org » bouncycastle » mail » smime » validator » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Security » Bouncy Castle » org.bouncycastle.mail.smime.validator 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package org.bouncycastle.mail.smime.validator;
002:
003:        import org.bouncycastle.asn1.ASN1InputStream;
004:        import org.bouncycastle.asn1.ASN1OctetString;
005:        import org.bouncycastle.asn1.ASN1TaggedObject;
006:        import org.bouncycastle.asn1.DERIA5String;
007:        import org.bouncycastle.asn1.DERObject;
008:        import org.bouncycastle.asn1.DEROctetString;
009:        import org.bouncycastle.asn1.DERSequence;
010:        import org.bouncycastle.asn1.cms.Attribute;
011:        import org.bouncycastle.asn1.cms.AttributeTable;
012:        import org.bouncycastle.asn1.cms.CMSAttributes;
013:        import org.bouncycastle.asn1.cms.Time;
014:        import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
015:        import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
016:        import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
017:        import org.bouncycastle.asn1.x509.KeyPurposeId;
018:        import org.bouncycastle.asn1.x509.X509Extensions;
019:        import org.bouncycastle.cms.SignerInformation;
020:        import org.bouncycastle.cms.SignerInformationStore;
021:        import org.bouncycastle.i18n.ErrorBundle;
022:        import org.bouncycastle.i18n.filter.TrustedInput;
023:        import org.bouncycastle.i18n.filter.UntrustedInput;
024:        import org.bouncycastle.jce.PrincipalUtil;
025:        import org.bouncycastle.jce.X509Principal;
026:        import org.bouncycastle.mail.smime.SMIMESigned;
027:        import org.bouncycastle.x509.CertPathReviewerException;
028:        import org.bouncycastle.x509.PKIXCertPathReviewer;
029:
030:        import javax.mail.Address;
031:        import javax.mail.internet.InternetAddress;
032:        import javax.mail.internet.MimeMessage;
033:        import javax.mail.internet.MimeMultipart;
034:        import java.io.IOException;
035:        import java.security.GeneralSecurityException;
036:        import java.security.PublicKey;
037:        import java.security.cert.CertPath;
038:        import java.security.cert.CertStore;
039:        import java.security.cert.CertStoreException;
040:        import java.security.cert.CertificateEncodingException;
041:        import java.security.cert.CertificateExpiredException;
042:        import java.security.cert.CertificateFactory;
043:        import java.security.cert.CertificateNotYetValidException;
044:        import java.security.cert.PKIXParameters;
045:        import java.security.cert.TrustAnchor;
046:        import java.security.cert.X509CertSelector;
047:        import java.security.cert.X509Certificate;
048:        import java.security.interfaces.DSAPublicKey;
049:        import java.security.interfaces.RSAPublicKey;
050:        import java.util.ArrayList;
051:        import java.util.Arrays;
052:        import java.util.Collection;
053:        import java.util.Date;
054:        import java.util.HashMap;
055:        import java.util.HashSet;
056:        import java.util.Iterator;
057:        import java.util.LinkedHashSet;
058:        import java.util.List;
059:        import java.util.Map;
060:        import java.util.Set;
061:        import java.util.Vector;
062:
063:        public class SignedMailValidator {
064:            private static final String RESOURCE_NAME = "org.bouncycastle.mail.smime.validator.SignedMailValidatorMessages";
065:
066:            private static final Class DEFAULT_CERT_PATH_REVIEWER = PKIXCertPathReviewer.class;
067:
068:            private static final String EXT_KEY_USAGE = X509Extensions.ExtendedKeyUsage
069:                    .getId();
070:
071:            private static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName
072:                    .getId();
073:
074:            private static final int shortKeyLength = 512;
075:
076:            // (365.25*30)*24*3600*1000
077:            private static final long THIRTY_YEARS_IN_MILLI_SEC = 21915l * 12l * 3600l * 1000l;
078:
079:            private CertStore certs;
080:
081:            private SignerInformationStore signers;
082:
083:            private Map results;
084:
085:            private String[] fromAddresses;
086:
087:            private Class certPathReviewerClass;
088:
089:            /**
090:             * Validates the signed {@link MimeMessage} message. The
091:             * {@link PKIXParameters} from param are used for the certificate path
092:             * validation. The actual PKIXParameters used for the certificate path
093:             * validation is a copy of param with the followin changes: <br> - The
094:             * validation date is changed to the signature time <br> - A CertStore with
095:             * certificates and crls from the mail message is added to the CertStores.<br>
096:             * <br>
097:             * In <code>param</code> it's also possible to add additional CertStores
098:             * with intermediate Certificates and/or CRLs which then are also used for
099:             * the validation.
100:             * 
101:             * @param message
102:             *            the signed MimeMessage
103:             * @param param
104:             *            the parameters for the certificate path validation 
105:             * @throws SignedMailValidatorException
106:             *             if the message is no signed message or if an exception occurs
107:             *             reading the message
108:             */
109:            public SignedMailValidator(MimeMessage message, PKIXParameters param)
110:                    throws SignedMailValidatorException {
111:                this (message, param, DEFAULT_CERT_PATH_REVIEWER);
112:            }
113:
114:            /**
115:             * Validates the signed {@link MimeMessage} message. The
116:             * {@link PKIXParameters} from param are used for the certificate path
117:             * validation. The actual PKIXParameters used for the certificate path
118:             * validation is a copy of param with the followin changes: <br> - The
119:             * validation date is changed to the signature time <br> - A CertStore with
120:             * certificates and crls from the mail message is added to the CertStores.<br>
121:             * <br>
122:             * In <code>param</code> it's also possible to add additional CertStores
123:             * with intermediate Certificates and/or CRLs which then are also used for
124:             * the validation.
125:             * 
126:             * @param message
127:             *            the signed MimeMessage
128:             * @param param
129:             *            the parameters for the certificate path validation
130:             * @param certPathReviewerClass
131:             *            a subclass of {@link PKIXCertPathReviewer}. The SignedMailValidator
132:             *            uses objects of this type for the cert path vailidation. The class must
133:             *            have an empty constructor.
134:             * @throws SignedMailValidatorException
135:             *             if the message is no signed message or if an exception occurs
136:             *             reading the message
137:             * @throws IllegalArgumentException if the certPathReviewerClass is not a 
138:             *             subclass of {@link PKIXCertPathReviewer} or objects of 
139:             *             certPathReviewerClass can not be instantiated
140:             */
141:            public SignedMailValidator(MimeMessage message,
142:                    PKIXParameters param, Class certPathReviewerClass)
143:                    throws SignedMailValidatorException {
144:                this .certPathReviewerClass = certPathReviewerClass;
145:                try {
146:                    certPathReviewerClass
147:                            .asSubclass(DEFAULT_CERT_PATH_REVIEWER);
148:                } catch (ClassCastException e) {
149:                    throw new IllegalArgumentException(
150:                            "certPathReviewerClass is not a subclass of "
151:                                    + DEFAULT_CERT_PATH_REVIEWER.getName());
152:                }
153:
154:                SMIMESigned s;
155:
156:                try {
157:                    // check if message is multipart signed
158:                    if (message.isMimeType("multipart/signed")) {
159:                        MimeMultipart mimemp = (MimeMultipart) message
160:                                .getContent();
161:                        s = new SMIMESigned(mimemp);
162:                    } else if (message.isMimeType("application/pkcs7-mime")
163:                            || message.isMimeType("application/x-pkcs7-mime")) {
164:                        s = new SMIMESigned(message);
165:                    } else {
166:                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
167:                                "SignedMailValidator.noSignedMessage");
168:                        throw new SignedMailValidatorException(msg);
169:                    }
170:
171:                    // save certstore and signerInformationStore
172:                    certs = s.getCertificatesAndCRLs("Collection", "BC");
173:                    signers = s.getSignerInfos();
174:
175:                    // save "from" addresses from message
176:                    Address[] froms = message.getFrom();
177:                    fromAddresses = new String[froms.length];
178:                    for (int i = 0; i < froms.length; i++) {
179:                        InternetAddress inetAddr = (InternetAddress) froms[i];
180:                        fromAddresses[i] = inetAddr.getAddress();
181:                    }
182:
183:                    // initialize results
184:                    results = new HashMap();
185:                } catch (Exception e) {
186:                    if (e instanceof  SignedMailValidatorException) {
187:                        throw (SignedMailValidatorException) e;
188:                    }
189:                    // exception reading message
190:                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
191:                            "SignedMailValidator.exceptionReadingMessage",
192:                            new Object[] { e.getMessage(), e,
193:                                    e.getClass().getName() });
194:                    throw new SignedMailValidatorException(msg, e);
195:                }
196:
197:                // validate signatues
198:                validateSignatures(param);
199:            }
200:
201:            protected void validateSignatures(PKIXParameters pkixParam) {
202:                PKIXParameters usedParameters = (PKIXParameters) pkixParam
203:                        .clone();
204:
205:                // add crls and certs from mail
206:                usedParameters.addCertStore(certs);
207:
208:                Collection c = signers.getSigners();
209:                Iterator it = c.iterator();
210:
211:                // check each signer
212:                while (it.hasNext()) {
213:                    List errors = new ArrayList();
214:                    List notifications = new ArrayList();
215:
216:                    SignerInformation signer = (SignerInformation) it.next();
217:                    // signer certificate
218:                    X509Certificate cert = null;
219:
220:                    try {
221:                        Collection certCollection = findCerts(usedParameters
222:                                .getCertStores(), signer.getSID());
223:
224:                        Iterator certIt = certCollection.iterator();
225:                        if (certIt.hasNext()) {
226:                            cert = (X509Certificate) certIt.next();
227:                        }
228:                    } catch (CertStoreException cse) {
229:                        ErrorBundle msg = new ErrorBundle(
230:                                RESOURCE_NAME,
231:                                "SignedMailValidator.exceptionRetrievingSignerCert",
232:                                new Object[] { cse.getMessage(), cse,
233:                                        cse.getClass().getName() });
234:                        errors.add(msg);
235:                    }
236:
237:                    if (cert != null) {
238:                        // check signature
239:                        boolean validSignature = false;
240:                        try {
241:                            validSignature = signer.verify(cert.getPublicKey(),
242:                                    "BC");
243:                            if (!validSignature) {
244:                                ErrorBundle msg = new ErrorBundle(
245:                                        RESOURCE_NAME,
246:                                        "SignedMailValidator.signatureNotVerified");
247:                                errors.add(msg);
248:                            }
249:                        } catch (Exception e) {
250:                            ErrorBundle msg = new ErrorBundle(
251:                                    RESOURCE_NAME,
252:                                    "SignedMailValidator.exceptionVerifyingSignature",
253:                                    new Object[] { e.getMessage(), e,
254:                                            e.getClass().getName() });
255:                            errors.add(msg);
256:                        }
257:
258:                        // check signer certificate (mail address, key usage, etc)
259:                        checkSignerCert(cert, errors, notifications);
260:
261:                        // notify if a signed receip request is in the message
262:                        AttributeTable atab = signer.getSignedAttributes();
263:                        if (atab != null) {
264:                            Attribute attr = atab
265:                                    .get(PKCSObjectIdentifiers.id_aa_receiptRequest);
266:                            if (attr != null) {
267:                                ErrorBundle msg = new ErrorBundle(
268:                                        RESOURCE_NAME,
269:                                        "SignedMailValidator.signedReceiptRequest");
270:                                notifications.add(msg);
271:                            }
272:                        }
273:
274:                        // check certificate path
275:
276:                        // get signing time if possible, otherwise use current time as
277:                        // signing time
278:                        Date signTime = getSignatureTime(signer);
279:                        if (signTime == null) // no signing time was found
280:                        {
281:                            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
282:                                    "SignedMailValidator.noSigningTime");
283:                            errors.add(msg);
284:                            signTime = new Date();
285:                        } else {
286:                            // check if certificate was valid at signing time
287:                            try {
288:                                cert.checkValidity(signTime);
289:                            } catch (CertificateExpiredException e) {
290:                                ErrorBundle msg = new ErrorBundle(
291:                                        RESOURCE_NAME,
292:                                        "SignedMailValidator.certExpired",
293:                                        new Object[] {
294:                                                new TrustedInput(signTime),
295:                                                new TrustedInput(cert
296:                                                        .getNotAfter()) });
297:                                errors.add(msg);
298:                            } catch (CertificateNotYetValidException e) {
299:                                ErrorBundle msg = new ErrorBundle(
300:                                        RESOURCE_NAME,
301:                                        "SignedMailValidator.certNotYetValid",
302:                                        new Object[] {
303:                                                new TrustedInput(signTime),
304:                                                new TrustedInput(cert
305:                                                        .getNotBefore()) });
306:                                errors.add(msg);
307:                            }
308:                        }
309:                        usedParameters.setDate(signTime);
310:
311:                        try {
312:                            // construct cert chain
313:                            CertPath certPath;
314:                            List userProvidedList;
315:
316:                            List userCertStores = new ArrayList();
317:                            userCertStores.add(certs);
318:                            Object[] cpres = createCertPath(cert,
319:                                    usedParameters.getTrustAnchors(), pkixParam
320:                                            .getCertStores(), userCertStores);
321:                            certPath = (CertPath) cpres[0];
322:                            userProvidedList = (List) cpres[1];
323:
324:                            // validate cert chain
325:                            PKIXCertPathReviewer review;
326:                            try {
327:                                review = (PKIXCertPathReviewer) certPathReviewerClass
328:                                        .newInstance();
329:                            } catch (IllegalAccessException e) {
330:                                throw new IllegalArgumentException(
331:                                        "Cannot instantiate object of type "
332:                                                + certPathReviewerClass
333:                                                        .getName() + ": "
334:                                                + e.getMessage(), e);
335:                            } catch (InstantiationException e) {
336:                                throw new IllegalArgumentException(
337:                                        "Cannot instantiate object of type "
338:                                                + certPathReviewerClass
339:                                                        .getName() + ": "
340:                                                + e.getMessage(), e);
341:                            }
342:                            review.init(certPath, usedParameters);
343:                            if (!review.isValidCertPath()) {
344:                                ErrorBundle msg = new ErrorBundle(
345:                                        RESOURCE_NAME,
346:                                        "SignedMailValidator.certPathInvalid");
347:                                errors.add(msg);
348:                            }
349:                            results.put(signer, new ValidationResult(review,
350:                                    validSignature, errors, notifications,
351:                                    userProvidedList));
352:                        } catch (GeneralSecurityException gse) {
353:                            // cannot create cert path
354:                            ErrorBundle msg = new ErrorBundle(
355:                                    RESOURCE_NAME,
356:                                    "SignedMailValidator.exceptionCreateCertPath",
357:                                    new Object[] { gse.getMessage(), gse,
358:                                            gse.getClass().getName() });
359:                            errors.add(msg);
360:                            results.put(signer,
361:                                    new ValidationResult(null, validSignature,
362:                                            errors, notifications, null));
363:                        } catch (CertPathReviewerException cpre) {
364:                            // cannot initialize certpathreviewer - wrong parameters
365:                            errors.add(cpre.getErrorMessage());
366:                            results.put(signer,
367:                                    new ValidationResult(null, validSignature,
368:                                            errors, notifications, null));
369:                        }
370:                    } else
371:                    // no signer certificate found
372:                    {
373:                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
374:                                "SignedMailValidator.noSignerCert");
375:                        errors.add(msg);
376:                        results.put(signer, new ValidationResult(null, false,
377:                                errors, notifications, null));
378:                    }
379:                }
380:            }
381:
382:            public static Set getEmailAddresses(X509Certificate cert)
383:                    throws IOException, CertificateEncodingException {
384:                Set addresses = new HashSet();
385:
386:                X509Principal name = PrincipalUtil
387:                        .getSubjectX509Principal(cert);
388:                Vector oids = name.getOIDs();
389:                Vector names = name.getValues();
390:                for (int i = 0; i < oids.size(); i++) {
391:                    if (oids.get(i).equals(X509Principal.EmailAddress)) {
392:                        String email = ((String) names.get(i)).toLowerCase();
393:                        addresses.add(email);
394:                        break;
395:                    }
396:                }
397:
398:                byte[] ext = cert.getExtensionValue(SUBJECT_ALTERNATIVE_NAME);
399:                if (ext != null) {
400:                    DERSequence altNames = (DERSequence) getObject(ext);
401:                    for (int j = 0; j < altNames.size(); j++) {
402:                        ASN1TaggedObject o = (ASN1TaggedObject) altNames
403:                                .getObjectAt(j);
404:
405:                        if (o.getTagNo() == 1) {
406:                            String email = DERIA5String.getInstance(o, true)
407:                                    .getString().toLowerCase();
408:                            addresses.add(email);
409:                        }
410:                    }
411:                }
412:
413:                return addresses;
414:            }
415:
416:            private static DERObject getObject(byte[] ext) throws IOException {
417:                ASN1InputStream aIn = new ASN1InputStream(ext);
418:                ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
419:
420:                aIn = new ASN1InputStream(octs.getOctets());
421:                return aIn.readObject();
422:            }
423:
424:            protected void checkSignerCert(X509Certificate cert, List errors,
425:                    List notifications) {
426:                // get key length
427:                PublicKey key = cert.getPublicKey();
428:                int keyLenght = -1;
429:                if (key instanceof  RSAPublicKey) {
430:                    keyLenght = ((RSAPublicKey) key).getModulus().bitLength();
431:                } else if (key instanceof  DSAPublicKey) {
432:                    keyLenght = ((DSAPublicKey) key).getParams().getP()
433:                            .bitLength();
434:                }
435:                if (keyLenght != -1 && keyLenght <= shortKeyLength) {
436:                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
437:                            "SignedMailValidator.shortSigningKey",
438:                            new Object[] { new Integer(keyLenght) });
439:                    notifications.add(msg);
440:                }
441:
442:                // warn if certificate has very long validity period
443:                long validityPeriod = cert.getNotAfter().getTime()
444:                        - cert.getNotBefore().getTime();
445:                if (validityPeriod > THIRTY_YEARS_IN_MILLI_SEC) {
446:                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
447:                            "SignedMailValidator.longValidity", new Object[] {
448:                                    new TrustedInput(cert.getNotBefore()),
449:                                    new TrustedInput(cert.getNotAfter()) });
450:                    notifications.add(msg);
451:                }
452:
453:                // check key usage if digitalSignature or nonRepudiation is set
454:                boolean[] keyUsage = cert.getKeyUsage();
455:                if (keyUsage != null && !keyUsage[0] && !keyUsage[1]) {
456:                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
457:                            "SignedMailValidator.signingNotPermitted");
458:                    errors.add(msg);
459:                }
460:
461:                // check extended key usage
462:                try {
463:                    byte[] ext = cert.getExtensionValue(EXT_KEY_USAGE);
464:                    if (ext != null) {
465:                        ExtendedKeyUsage extKeyUsage = ExtendedKeyUsage
466:                                .getInstance(getObject(ext));
467:                        if (!extKeyUsage
468:                                .hasKeyPurposeId(KeyPurposeId.anyExtendedKeyUsage)
469:                                && !extKeyUsage
470:                                        .hasKeyPurposeId(KeyPurposeId.id_kp_emailProtection)) {
471:                            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
472:                                    "SignedMailValidator.extKeyUsageNotPermitted");
473:                            errors.add(msg);
474:                        }
475:                    }
476:                } catch (Exception e) {
477:                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
478:                            "SignedMailValidator.extKeyUsageError",
479:                            new Object[] { e.getMessage(), e,
480:                                    e.getClass().getName() });
481:                    errors.add(msg);
482:                }
483:
484:                // cert has an email address
485:                try {
486:                    Set certEmails = getEmailAddresses(cert);
487:                    if (certEmails.isEmpty()) {
488:                        // error no email address in signing certificate
489:                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
490:                                "SignedMailValidator.noEmailInCert");
491:                        errors.add(msg);
492:                    } else {
493:                        // check if email in cert is equal to the from address in the
494:                        // message
495:                        boolean equalsFrom = false;
496:                        for (int i = 0; i < fromAddresses.length; i++) {
497:                            if (certEmails.contains(fromAddresses[i]
498:                                    .toLowerCase())) {
499:                                equalsFrom = true;
500:                                break;
501:                            }
502:                        }
503:                        if (!equalsFrom) {
504:                            ErrorBundle msg = new ErrorBundle(
505:                                    RESOURCE_NAME,
506:                                    "SignedMailValidator.emailFromCertMismatch",
507:                                    new Object[] {
508:                                            new UntrustedInput(Arrays
509:                                                    .toString(fromAddresses)),
510:                                            new UntrustedInput(certEmails) });
511:                            errors.add(msg);
512:                        }
513:                    }
514:                } catch (Exception e) {
515:                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
516:                            "SignedMailValidator.certGetEmailError",
517:                            new Object[] { e.getMessage(), e,
518:                                    e.getClass().getName() });
519:                    errors.add(msg);
520:                }
521:            }
522:
523:            public static Date getSignatureTime(SignerInformation signer) {
524:                AttributeTable atab = signer.getSignedAttributes();
525:                Date result = null;
526:                if (atab != null) {
527:                    Attribute attr = atab.get(CMSAttributes.signingTime);
528:                    if (attr != null) {
529:                        Time t = Time.getInstance(attr.getAttrValues()
530:                                .getObjectAt(0).getDERObject());
531:                        result = t.getDate();
532:                    }
533:                }
534:                return result;
535:            }
536:
537:            private static List findCerts(List certStores,
538:                    X509CertSelector selector) throws CertStoreException {
539:                List result = new ArrayList();
540:                Iterator it = certStores.iterator();
541:                while (it.hasNext()) {
542:                    CertStore store = (CertStore) it.next();
543:                    Collection coll = store.getCertificates(selector);
544:                    result.addAll(coll);
545:                }
546:                return result;
547:            }
548:
549:            private static X509Certificate findNextCert(List certStores,
550:                    X509CertSelector selector, Set certSet)
551:                    throws CertStoreException {
552:                Iterator certIt = findCerts(certStores, selector).iterator();
553:
554:                boolean certFound = false;
555:                X509Certificate nextCert = null;
556:                while (certIt.hasNext()) {
557:                    nextCert = (X509Certificate) certIt.next();
558:                    if (!certSet.contains(nextCert)) {
559:                        certFound = true;
560:                        break;
561:                    }
562:                }
563:
564:                return certFound ? nextCert : null;
565:            }
566:
567:            /**
568:             * 
569:             * @param signerCert the end of the path
570:             * @param trustanchors trust anchors for the path
571:             * @param certStores
572:             * @return the resulting certificate path.
573:             * @throws GeneralSecurityException
574:             */
575:            public static CertPath createCertPath(X509Certificate signerCert,
576:                    Set trustanchors, List certStores)
577:                    throws GeneralSecurityException {
578:                Object[] results = createCertPath(signerCert, trustanchors,
579:                        certStores, null);
580:                return (CertPath) results[0];
581:            }
582:
583:            /**
584:             * Returns an Object array containing a CertPath and a List of Booleans. The list contains the value <code>true</code>
585:             * if the corresponding certificate in the CertPath was taken from the user provided CertStores.
586:             * @param signerCert the end of the path
587:             * @param trustanchors trust anchors for the path
588:             * @param systemCertStores list of {@link CertStore} provided by the system
589:             * @param userCertStores list of {@link CertStore} provided by the user
590:             * @return a CertPath and a List of booleans.
591:             * @throws GeneralSecurityException
592:             */
593:            public static Object[] createCertPath(X509Certificate signerCert,
594:                    Set trustanchors, List systemCertStores, List userCertStores)
595:                    throws GeneralSecurityException {
596:                Set certSet = new LinkedHashSet();
597:                List userProvidedList = new ArrayList();
598:
599:                // add signer certificate
600:
601:                X509Certificate cert = signerCert;
602:                certSet.add(cert);
603:                userProvidedList.add(new Boolean(true));
604:
605:                boolean trustAnchorFound = false;
606:
607:                X509Certificate taCert = null;
608:
609:                // add other certs to the cert path
610:                while (cert != null && !trustAnchorFound) {
611:                    // check if cert Issuer is Trustanchor
612:                    Iterator trustIt = trustanchors.iterator();
613:                    while (trustIt.hasNext()) {
614:                        TrustAnchor anchor = (TrustAnchor) trustIt.next();
615:                        X509Certificate anchorCert = anchor.getTrustedCert();
616:                        if (anchorCert != null) {
617:                            if (anchorCert.getSubjectX500Principal().equals(
618:                                    cert.getIssuerX500Principal())) {
619:                                try {
620:                                    cert
621:                                            .verify(anchorCert.getPublicKey(),
622:                                                    "BC");
623:                                    trustAnchorFound = true;
624:                                    taCert = anchorCert;
625:                                    break;
626:                                } catch (Exception e) {
627:                                    // trustanchor not found
628:                                }
629:                            }
630:                        } else {
631:                            if (anchor.getCAName().equals(
632:                                    cert.getIssuerX500Principal().getName())) {
633:                                try {
634:                                    cert.verify(anchor.getCAPublicKey(), "BC");
635:                                    trustAnchorFound = true;
636:                                    break;
637:                                } catch (Exception e) {
638:                                    // trustanchor not found
639:                                }
640:                            }
641:                        }
642:                    }
643:
644:                    if (!trustAnchorFound) {
645:                        // add next cert to path
646:                        X509CertSelector select = new X509CertSelector();
647:                        select.setSubject(cert.getIssuerX500Principal());
648:                        byte[] authKeyIdentBytes = cert
649:                                .getExtensionValue(X509Extensions.AuthorityKeyIdentifier
650:                                        .getId());
651:                        if (authKeyIdentBytes != null) {
652:                            try {
653:                                AuthorityKeyIdentifier kid = AuthorityKeyIdentifier
654:                                        .getInstance(getObject(authKeyIdentBytes));
655:                                if (kid.getKeyIdentifier() != null) {
656:                                    select
657:                                            .setSubjectKeyIdentifier(new DEROctetString(
658:                                                    kid.getKeyIdentifier())
659:                                                    .getDEREncoded());
660:                                }
661:                            } catch (IOException ioe) {
662:                                // ignore
663:                            }
664:                        }
665:                        boolean userProvided = false;
666:
667:                        cert = findNextCert(systemCertStores, select, certSet);
668:                        if (cert == null && userCertStores != null) {
669:                            userProvided = true;
670:                            cert = findNextCert(userCertStores, select, certSet);
671:                        }
672:
673:                        if (cert != null) {
674:                            // cert found
675:                            certSet.add(cert);
676:                            userProvidedList.add(new Boolean(userProvided));
677:                        }
678:                    }
679:                }
680:
681:                // if a trustanchor was found - try to find a selfsigned certificate of
682:                // the trustanchor
683:                if (trustAnchorFound) {
684:                    if (taCert != null
685:                            && taCert.getSubjectX500Principal().equals(
686:                                    taCert.getIssuerX500Principal())) {
687:                        certSet.add(taCert);
688:                        userProvidedList.add(new Boolean(false));
689:                    } else {
690:                        X509CertSelector select = new X509CertSelector();
691:                        select.setSubject(cert.getIssuerX500Principal());
692:                        select.setIssuer(cert.getIssuerX500Principal());
693:
694:                        boolean userProvided = false;
695:
696:                        taCert = findNextCert(systemCertStores, select, certSet);
697:                        if (taCert == null && userCertStores != null) {
698:                            userProvided = true;
699:                            taCert = findNextCert(userCertStores, select,
700:                                    certSet);
701:                        }
702:                        if (taCert != null) {
703:                            try {
704:                                cert.verify(taCert.getPublicKey(), "BC");
705:                                certSet.add(taCert);
706:                                userProvidedList.add(new Boolean(userProvided));
707:                            } catch (GeneralSecurityException gse) {
708:                                // wrong cert
709:                            }
710:                        }
711:                    }
712:                }
713:
714:                CertPath certPath = CertificateFactory.getInstance("X.509",
715:                        "BC").generateCertPath(new ArrayList(certSet));
716:                return new Object[] { certPath, userProvidedList };
717:            }
718:
719:            public CertStore getCertsAndCRLs() {
720:                return certs;
721:            }
722:
723:            public SignerInformationStore getSignerInformationStore() {
724:                return signers;
725:            }
726:
727:            public ValidationResult getValidationResult(SignerInformation signer)
728:                    throws SignedMailValidatorException {
729:                if (signers.getSigners(signer.getSID()).isEmpty()) {
730:                    // the signer is not part of the SignerInformationStore
731:                    // he has not signed the message
732:                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
733:                            "SignedMailValidator.wrongSigner");
734:                    throw new SignedMailValidatorException(msg);
735:                } else {
736:                    return (ValidationResult) results.get(signer);
737:                }
738:            }
739:
740:            public class ValidationResult {
741:
742:                private PKIXCertPathReviewer review;
743:
744:                private List errors;
745:
746:                private List notifications;
747:
748:                private List userProvidedCerts;
749:
750:                private boolean signVerified;
751:
752:                ValidationResult(PKIXCertPathReviewer review, boolean verified,
753:                        List errors, List notifications, List userProvidedCerts) {
754:                    this .review = review;
755:                    this .errors = errors;
756:                    this .notifications = notifications;
757:                    signVerified = verified;
758:                    this .userProvidedCerts = userProvidedCerts;
759:                }
760:
761:                /**
762:                 * Returns a list of error messages of type {@link ErrorBundle}.
763:                 * 
764:                 * @return List of error messages
765:                 */
766:                public List getErrors() {
767:                    return errors;
768:                }
769:
770:                /**
771:                 * Returns a list of notification messages of type {@link ErrorBundle}.
772:                 * 
773:                 * @return List of notification messages
774:                 */
775:                public List getNotifications() {
776:                    return notifications;
777:                }
778:
779:                /**
780:                 * 
781:                 * @return the PKIXCertPathReviewer for the CertPath of this signature
782:                 *         or null if an Exception occured.
783:                 */
784:                public PKIXCertPathReviewer getCertPathReview() {
785:                    return review;
786:                }
787:
788:                /**
789:                 * 
790:                 * @return the CertPath for this signature
791:                 *         or null if an Exception occured.
792:                 */
793:                public CertPath getCertPath() {
794:                    return review != null ? review.getCertPath() : null;
795:                }
796:
797:                /**
798:                 * 
799:                 * @return a List of Booleans that are true if the corresponding certificate in the CertPath was taken from
800:                 * the CertStore of the SMIME message
801:                 */
802:                public List getUserProvidedCerts() {
803:                    return userProvidedCerts;
804:                }
805:
806:                /**
807:                 * 
808:                 * @return true if the signature corresponds to the public key of the
809:                 *         signer
810:                 */
811:                public boolean isVerifiedSignature() {
812:                    return signVerified;
813:                }
814:
815:                /**
816:                 * 
817:                 * @return true if the signature is valid (ie. if it corresponds to the
818:                 *         public key of the signer and the cert path for the signers
819:                 *         certificate is also valid)
820:                 */
821:                public boolean isValidSignature() {
822:                    if (review != null) {
823:                        return signVerified && review.isValidCertPath()
824:                                && errors.isEmpty();
825:                    } else {
826:                        return false;
827:                    }
828:                }
829:
830:            }
831:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.