1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.security.x509;
27
28 import java.io.IOException;
29 import java.io.OutputStream;
30 import java.security.cert.CertificateException;
31 import java.security.cert.X509Certificate;
32 import java.util.*;
33
34 import javax.security.auth.x500.X500Principal;
35
36 import sun.security.util.*;
37 import sun.security.pkcs.PKCS9Attribute;
38
39 /**
40 * This class defines the Name Constraints Extension.
41 * <p>
42 * The name constraints extension provides permitted and excluded
43 * subtrees that place restrictions on names that may be included within
44 * a certificate issued by a given CA. Restrictions may apply to the
45 * subject distinguished name or subject alternative names. Any name
46 * matching a restriction in the excluded subtrees field is invalid
47 * regardless of information appearing in the permitted subtrees.
48 * <p>
49 * The ASN.1 syntax for this is:
50 * <pre>
51 * NameConstraints ::= SEQUENCE {
52 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
53 * excludedSubtrees [1] GeneralSubtrees OPTIONAL
54 * }
55 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
416 }
417
418 // Calculate hasMin and hasMax booleans (if necessary)
419 if (!minMaxValid) {
420 calcMinMax();
421 }
422
423 if (hasMin) {
424 throw new IOException("Non-zero minimum BaseDistance in"
425 + " name constraints not supported");
426 }
427
428 if (hasMax) {
429 throw new IOException("Maximum BaseDistance in"
430 + " name constraints not supported");
431 }
432
433 X500Principal subjectPrincipal = cert.getSubjectX500Principal();
434 X500Name subject = X500Name.asX500Name(subjectPrincipal);
435
436 if (subject.isEmpty() == false) {
437 if (verify(subject) == false) {
438 return false;
439 }
440 }
441
442 GeneralNames altNames = null;
443 // extract altNames
444 try {
445 // extract extensions, if any, from certInfo
446 // following returns null if certificate contains no extensions
447 X509CertImpl certImpl = X509CertImpl.toImpl(cert);
448 SubjectAlternativeNameExtension altNameExt =
449 certImpl.getSubjectAlternativeNameExtension();
450 if (altNameExt != null) {
451 // extract altNames from extension; this call does not
452 // return an IOException on null altnames
453 altNames = altNameExt.get(
454 SubjectAlternativeNameExtension.SUBJECT_NAME);
455 }
456 } catch (CertificateException ce) {
457 throw new IOException("Unable to extract extensions from " +
458 "certificate: " + ce.getMessage());
459 }
460
461 // If there are no subjectAlternativeNames, perform the special-case
462 // check where if the subjectName contains any EMAILADDRESS
463 // attributes, they must be checked against RFC822 constraints.
464 // If that passes, we're fine.
465 if (altNames == null) {
466 return verifyRFC822SpecialCase(subject);
467 }
468
469 // verify each subjectAltName
470 for (int i = 0; i < altNames.size(); i++) {
471 GeneralNameInterface altGNI = altNames.get(i).getName();
472 if (!verify(altGNI)) {
473 return false;
474 }
475 }
476
477 // All tests passed.
478 return true;
479 }
480
481 /**
482 * check whether a name conforms to these NameConstraints.
483 * This involves verifying that the name is consistent with the
484 * permitted and excluded subtrees variables.
485 *
486 * @param name GeneralNameInterface name to be verified
487 * @returns true if certificate verifies successfully
488 * @throws IOException on error
489 */
490 public boolean verify(GeneralNameInterface name) throws IOException {
491 if (name == null) {
492 throw new IOException("name is null");
493 }
494
495 // Verify that the name is consistent with the excluded subtrees
496 if (excluded != null && excluded.size() > 0) {
497
498 for (int i = 0; i < excluded.size(); i++) {
499 GeneralSubtree gs = excluded.get(i);
500 if (gs == null)
538
539 // if Name matches any type in permitted,
540 // and Name does not match or narrow some permitted subtree,
541 // return false
542 switch (perName.constrains(name)) {
543 case GeneralNameInterface.NAME_DIFF_TYPE:
544 continue; // continue checking other permitted names
545 case GeneralNameInterface.NAME_WIDENS: // name widens permitted
546 case GeneralNameInterface.NAME_SAME_TYPE:
547 sameType = true;
548 continue; // continue to look for a match or narrow
549 case GeneralNameInterface.NAME_MATCH:
550 case GeneralNameInterface.NAME_NARROWS:
551 // name narrows permitted
552 return true; // name is definitely OK, so break out of loop
553 }
554 }
555 if (sameType) {
556 return false;
557 }
558 }
559 return true;
560 }
561
562 /**
563 * Perform the RFC 822 special case check. We have a certificate
564 * that does not contain any subject alternative names. Check that
565 * any EMAILADDRESS attributes in its subject name conform to these
566 * NameConstraints.
567 *
568 * @param subject the certificate's subject name
569 * @returns true if certificate verifies successfully
570 * @throws IOException on error
571 */
572 public boolean verifyRFC822SpecialCase(X500Name subject) throws IOException {
573 for (AVA ava : subject.allAvas()) {
574 ObjectIdentifier attrOID = ava.getObjectIdentifier();
575 if (attrOID.equals((Object)PKCS9Attribute.EMAIL_ADDRESS_OID)) {
576 String attrValue = ava.getValueString();
577 if (attrValue != null) {
578 RFC822Name emailName;
579 try {
580 emailName = new RFC822Name(attrValue);
581 } catch (IOException ioe) {
582 continue;
583 }
584 if (!verify(emailName)) {
585 return(false);
586 }
587 }
588 }
589 }
590 return true;
591 }
592
593 /**
594 * Clone all objects that may be modified during certificate validation.
595 */
596 public Object clone() {
597 try {
598 NameConstraintsExtension newNCE =
599 (NameConstraintsExtension) super.clone();
600
601 if (permitted != null) {
602 newNCE.permitted = (GeneralSubtrees) permitted.clone();
603 }
604 if (excluded != null) {
605 newNCE.excluded = (GeneralSubtrees) excluded.clone();
606 }
607 return newNCE;
608 } catch (CloneNotSupportedException cnsee) {
|
1 /*
2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.security.x509;
27
28 import java.io.IOException;
29 import java.io.OutputStream;
30 import java.security.cert.CertificateException;
31 import java.security.cert.X509Certificate;
32 import java.util.*;
33
34 import javax.security.auth.x500.X500Principal;
35
36 import sun.net.util.IPAddressUtil;
37 import sun.security.util.*;
38 import sun.security.pkcs.PKCS9Attribute;
39
40 /**
41 * This class defines the Name Constraints Extension.
42 * <p>
43 * The name constraints extension provides permitted and excluded
44 * subtrees that place restrictions on names that may be included within
45 * a certificate issued by a given CA. Restrictions may apply to the
46 * subject distinguished name or subject alternative names. Any name
47 * matching a restriction in the excluded subtrees field is invalid
48 * regardless of information appearing in the permitted subtrees.
49 * <p>
50 * The ASN.1 syntax for this is:
51 * <pre>
52 * NameConstraints ::= SEQUENCE {
53 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
54 * excludedSubtrees [1] GeneralSubtrees OPTIONAL
55 * }
56 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
417 }
418
419 // Calculate hasMin and hasMax booleans (if necessary)
420 if (!minMaxValid) {
421 calcMinMax();
422 }
423
424 if (hasMin) {
425 throw new IOException("Non-zero minimum BaseDistance in"
426 + " name constraints not supported");
427 }
428
429 if (hasMax) {
430 throw new IOException("Maximum BaseDistance in"
431 + " name constraints not supported");
432 }
433
434 X500Principal subjectPrincipal = cert.getSubjectX500Principal();
435 X500Name subject = X500Name.asX500Name(subjectPrincipal);
436
437 // Check subject as an X500Name
438 if (subject.isEmpty() == false) {
439 if (verify(subject) == false) {
440 return false;
441 }
442 }
443
444 GeneralNames altNames = null;
445 // extract altNames
446 try {
447 // extract extensions, if any, from certInfo
448 // following returns null if certificate contains no extensions
449 X509CertImpl certImpl = X509CertImpl.toImpl(cert);
450 SubjectAlternativeNameExtension altNameExt =
451 certImpl.getSubjectAlternativeNameExtension();
452 if (altNameExt != null) {
453 // extract altNames from extension; this call does not
454 // return an IOException on null altnames
455 altNames = altNameExt.get(
456 SubjectAlternativeNameExtension.SUBJECT_NAME);
457 }
458 } catch (CertificateException ce) {
459 throw new IOException("Unable to extract extensions from " +
460 "certificate: " + ce.getMessage());
461 }
462
463 if (altNames == null) {
464 altNames = new GeneralNames();
465
466 // RFC 5280 4.2.1.10:
467 // When constraints are imposed on the rfc822Name name form,
468 // but the certificate does not include a subject alternative name,
469 // the rfc822Name constraint MUST be applied to the attribute of
470 // type emailAddress in the subject distinguished name.
471 for (AVA ava : subject.allAvas()) {
472 ObjectIdentifier attrOID = ava.getObjectIdentifier();
473 if (attrOID.equals(PKCS9Attribute.EMAIL_ADDRESS_OID)) {
474 String attrValue = ava.getValueString();
475 if (attrValue != null) {
476 try {
477 altNames.add(new GeneralName(
478 new RFC822Name(attrValue)));
479 } catch (IOException ioe) {
480 continue;
481 }
482 }
483 }
484 }
485 }
486
487 // If there is no IPAddressName or DNSName in subjectAlternativeNames,
488 // see if the last CN inside subjectName can be used instead.
489 DerValue derValue = subject.findMostSpecificAttribute
490 (X500Name.commonName_oid);
491 String cn = derValue == null ? null : derValue.getAsString();
492
493 if (cn != null) {
494 try {
495 if (IPAddressUtil.isIPv4LiteralAddress(cn) ||
496 IPAddressUtil.isIPv6LiteralAddress(cn)) {
497 if (!hasNameType(altNames, GeneralNameInterface.NAME_IP)) {
498 altNames.add(new GeneralName(new IPAddressName(cn)));
499 }
500 } else {
501 if (!hasNameType(altNames, GeneralNameInterface.NAME_DNS)) {
502 altNames.add(new GeneralName(new DNSName(cn)));
503 }
504 }
505 } catch (IOException ioe) {
506 // OK, cn is neither IP nor DNS
507 }
508 }
509
510 // verify each subjectAltName
511 for (int i = 0; i < altNames.size(); i++) {
512 GeneralNameInterface altGNI = altNames.get(i).getName();
513 if (!verify(altGNI)) {
514 return false;
515 }
516 }
517
518 // All tests passed.
519 return true;
520 }
521
522 private static boolean hasNameType(GeneralNames names, int type) {
523 for (GeneralName name : names.names()) {
524 if (name.getType() == type) {
525 return true;
526 }
527 }
528 return false;
529 }
530
531 /**
532 * check whether a name conforms to these NameConstraints.
533 * This involves verifying that the name is consistent with the
534 * permitted and excluded subtrees variables.
535 *
536 * @param name GeneralNameInterface name to be verified
537 * @returns true if certificate verifies successfully
538 * @throws IOException on error
539 */
540 public boolean verify(GeneralNameInterface name) throws IOException {
541 if (name == null) {
542 throw new IOException("name is null");
543 }
544
545 // Verify that the name is consistent with the excluded subtrees
546 if (excluded != null && excluded.size() > 0) {
547
548 for (int i = 0; i < excluded.size(); i++) {
549 GeneralSubtree gs = excluded.get(i);
550 if (gs == null)
588
589 // if Name matches any type in permitted,
590 // and Name does not match or narrow some permitted subtree,
591 // return false
592 switch (perName.constrains(name)) {
593 case GeneralNameInterface.NAME_DIFF_TYPE:
594 continue; // continue checking other permitted names
595 case GeneralNameInterface.NAME_WIDENS: // name widens permitted
596 case GeneralNameInterface.NAME_SAME_TYPE:
597 sameType = true;
598 continue; // continue to look for a match or narrow
599 case GeneralNameInterface.NAME_MATCH:
600 case GeneralNameInterface.NAME_NARROWS:
601 // name narrows permitted
602 return true; // name is definitely OK, so break out of loop
603 }
604 }
605 if (sameType) {
606 return false;
607 }
608 }
609 return true;
610 }
611
612 /**
613 * Clone all objects that may be modified during certificate validation.
614 */
615 public Object clone() {
616 try {
617 NameConstraintsExtension newNCE =
618 (NameConstraintsExtension) super.clone();
619
620 if (permitted != null) {
621 newNCE.permitted = (GeneralSubtrees) permitted.clone();
622 }
623 if (excluded != null) {
624 newNCE.excluded = (GeneralSubtrees) excluded.clone();
625 }
626 return newNCE;
627 } catch (CloneNotSupportedException cnsee) {
|