59 import pkg.client.pkgdefs as pkgdefs |
63 import pkg.client.pkgdefs as pkgdefs |
60 import pkg.digest as digest |
64 import pkg.digest as digest |
61 import pkg.misc as misc |
65 import pkg.misc as misc |
62 import pkg.portable as portable |
66 import pkg.portable as portable |
63 import pkg.server.catalog as old_catalog |
67 import pkg.server.catalog as old_catalog |
64 import M2Crypto as m2 |
|
65 |
68 |
66 from pkg.client import global_settings |
69 from pkg.client import global_settings |
67 from pkg.client.debugvalues import DebugValues |
70 from pkg.client.debugvalues import DebugValues |
68 logger = global_settings.logger |
71 logger = global_settings.logger |
69 from pkg.misc import EmptyDict, EmptyI, SIGNATURE_POLICY, DictProperty, \ |
72 from pkg.misc import EmptyDict, EmptyI, SIGNATURE_POLICY, DictProperty, \ |
99 # Sort policy mapping. |
102 # Sort policy mapping. |
100 URI_SORT_POLICIES = { |
103 URI_SORT_POLICIES = { |
101 URI_SORT_PRIORITY: lambda obj: (obj.priority, obj.uri), |
104 URI_SORT_PRIORITY: lambda obj: (obj.priority, obj.uri), |
102 } |
105 } |
103 |
106 |
104 # This dictionary records the recognized values of extensions. |
107 # The strings in the value field refer to the boolean properties of the |
|
108 # Cryptography extension classes. If a property has a value True set, it means |
|
109 # this property is added as an extension value in the certificate generation, |
|
110 # and vice versa. |
|
111 EXTENSIONS_VALUES = { |
|
112 x509.BasicConstraints: ["ca", "path_length"], |
|
113 x509.KeyUsage: ["digital_signature", "content_commitment", |
|
114 "key_encipherment", "data_encipherment", "key_agreement", "key_cert_sign", |
|
115 "crl_sign", "encipher_only", "decipher_only"] |
|
116 } |
|
117 |
|
118 # Only listed extension values (properties) here can have a value True set in a |
|
119 # certificate extension; any other properties with a value True set will be |
|
120 # treated as unsupported. |
105 SUPPORTED_EXTENSION_VALUES = { |
121 SUPPORTED_EXTENSION_VALUES = { |
106 "basicConstraints": ("CA:TRUE", "CA:FALSE", "PATHLEN:"), |
122 x509.BasicConstraints: ("ca", "path_length"), |
107 "keyUsage": ("DIGITAL SIGNATURE", "CERTIFICATE SIGN", "CRL SIGN") |
123 x509.KeyUsage: ("digital_signature", "key_cert_sign", "crl_sign") |
108 } |
124 } |
109 |
125 |
110 # These dictionaries map uses into their extensions. |
126 # These dictionaries map uses into their extensions. |
111 CODE_SIGNING_USE = { |
127 CODE_SIGNING_USE = { |
112 "keyUsage": ["DIGITAL SIGNATURE"] |
128 x509.KeyUsage: ["digital_signature"], |
113 } |
129 } |
114 |
130 |
115 CERT_SIGNING_USE = { |
131 CERT_SIGNING_USE = { |
116 "basicConstraints": ["CA:TRUE"], |
132 x509.BasicConstraints: ["ca"], |
117 "keyUsage": ["CERTIFICATE SIGN"] |
133 x509.KeyUsage: ["key_cert_sign"], |
118 } |
134 } |
119 |
135 |
120 CRL_SIGNING_USE = { |
136 CRL_SIGNING_USE = { |
121 "keyUsage": ["CRL SIGN"] |
137 x509.KeyUsage: ["crl_sign"], |
122 } |
138 } |
123 |
139 |
124 POSSIBLE_USES = [CODE_SIGNING_USE, CERT_SIGNING_USE, CRL_SIGNING_USE] |
140 POSSIBLE_USES = [CODE_SIGNING_USE, CERT_SIGNING_USE, CRL_SIGNING_USE] |
125 |
141 |
126 # A special token used in place of the system repository URL which is |
142 # A special token used in place of the system repository URL which is |
2442 |
2458 |
2443 @staticmethod |
2459 @staticmethod |
2444 def __hash_cert(c): |
2460 def __hash_cert(c): |
2445 # In order to interoperate with older images, we must use SHA-1 |
2461 # In order to interoperate with older images, we must use SHA-1 |
2446 # here. |
2462 # here. |
2447 return hashlib.sha1(c.as_pem()).hexdigest() |
2463 return hashlib.sha1( |
|
2464 c.public_bytes(serialization.Encoding.PEM)).hexdigest() |
2448 |
2465 |
2449 @staticmethod |
2466 @staticmethod |
2450 def __string_to_cert(s, pkg_hash=None): |
2467 def __string_to_cert(s, pkg_hash=None): |
2451 """Convert a string to a X509 cert.""" |
2468 """Convert a string to a X509 cert.""" |
2452 |
2469 |
2453 try: |
2470 try: |
2454 return m2.X509.load_cert_string(s) |
2471 return x509.load_pem_x509_certificate( |
2455 except m2.X509.X509Error as e: |
2472 misc.force_bytes(s), default_backend()) |
|
2473 except ValueError: |
2456 if pkg_hash is not None: |
2474 if pkg_hash is not None: |
2457 raise api_errors.BadFileFormat(_("The file " |
2475 raise api_errors.BadFileFormat(_("The file " |
2458 "with hash {0} was expected to be a PEM " |
2476 "with hash {0} was expected to be a PEM " |
2459 "certificate but it could not be " |
2477 "certificate but it could not be " |
2460 "read.").format(pkg_hash)) |
2478 "read.").format(pkg_hash)) |
2471 pkg_hash = self.__hash_cert(cert) |
2489 pkg_hash = self.__hash_cert(cert) |
2472 pkg_hash_pth = os.path.join(self.cert_root, pkg_hash) |
2490 pkg_hash_pth = os.path.join(self.cert_root, pkg_hash) |
2473 file_problem = False |
2491 file_problem = False |
2474 try: |
2492 try: |
2475 with open(pkg_hash_pth, "wb") as fh: |
2493 with open(pkg_hash_pth, "wb") as fh: |
2476 fh.write(cert.as_pem()) |
2494 fh.write(cert.public_bytes( |
|
2495 serialization.Encoding.PEM)) |
2477 except EnvironmentError as e: |
2496 except EnvironmentError as e: |
|
2497 if e.errno == errno.EACCES: |
|
2498 raise api_errors.PermissionsException( |
|
2499 e.filename) |
2478 file_problem = True |
2500 file_problem = True |
2479 |
2501 |
2480 # Note that while we store certs by their subject hashes, |
2502 # Note that while we store certs by their subject hashes, |
2481 # M2Crypto's subject hashes differ from what openssl reports |
2503 # we use our own hashing since cryptography has no interface |
2482 # the subject hash to be. |
2504 # for the subject hash and other crypto frameworks have been |
2483 subj_hsh = cert.get_subject().as_hash() |
2505 # inconsistent with OpenSSL. |
|
2506 subj_hsh = hashlib.sha1(misc.force_bytes( |
|
2507 cert.subject)).hexdigest() |
2484 c = 0 |
2508 c = 0 |
2485 made_link = False |
2509 made_link = False |
2486 while not made_link: |
2510 while not made_link: |
2487 fn = os.path.join(self.__subj_root, |
2511 fn = os.path.join(self.__subj_root, |
2488 "{0}.{1}".format(subj_hsh, c)) |
2512 "{0}.{1}".format(subj_hsh, c)) |
2542 if h != pkg_hash: |
2566 if h != pkg_hash: |
2543 raise api_errors.ModifiedCertificateException(c, |
2567 raise api_errors.ModifiedCertificateException(c, |
2544 pth) |
2568 pth) |
2545 return c |
2569 return c |
2546 |
2570 |
|
2571 def __rebuild_subj_root(self): |
|
2572 """Rebuild subject hash metadata.""" |
|
2573 |
|
2574 # clean up the old subject hash files to prevent |
|
2575 # junk files residing in the directory |
|
2576 try: |
|
2577 shutil.rmtree(self.__subj_root) |
|
2578 except EnvironmentError: |
|
2579 # if unprivileged user, we can't add |
|
2580 # certs to it |
|
2581 pass |
|
2582 else: |
|
2583 for p in os.listdir(self.cert_root): |
|
2584 path = os.path.join(self.cert_root, p) |
|
2585 if not os.path.isfile(path): |
|
2586 continue |
|
2587 with open(path, "rb") as fh: |
|
2588 s = fh.read() |
|
2589 cert = self.__string_to_cert(s) |
|
2590 self.__add_cert(cert) |
|
2591 |
2547 def __get_certs_by_name(self, name): |
2592 def __get_certs_by_name(self, name): |
2548 """Given 'name', a M2Crypto X509_Name, return the certs with |
2593 """Given 'name', a Cryptograhy 'Name' object, return the certs |
2549 that name as a subject.""" |
2594 with that name as a subject.""" |
2550 |
2595 |
2551 res = [] |
2596 res = [] |
2552 c = 0 |
2597 count = 0 |
2553 name_hsh = name.as_hash() |
2598 name_hsh = hashlib.sha1(misc.force_bytes(name)).hexdigest() |
|
2599 |
|
2600 def load_cert(pth): |
|
2601 with open(pth, "rb") as f: |
|
2602 return x509.load_pem_x509_certificate( |
|
2603 f.read(), default_backend()) |
|
2604 |
2554 try: |
2605 try: |
2555 while True: |
2606 while True: |
2556 pth = os.path.join(self.__subj_root, |
2607 pth = os.path.join(self.__subj_root, |
2557 "{0}.{1}".format(name_hsh, c)) |
2608 "{0}.{1}".format(name_hsh, count)) |
2558 cert = m2.X509.load_cert(pth) |
2609 res.append(load_cert(pth)) |
2559 res.append(cert) |
2610 count += 1 |
2560 c += 1 |
|
2561 except EnvironmentError as e: |
2611 except EnvironmentError as e: |
|
2612 # When switching to a different hash algorithm, the hash |
|
2613 # name of file changes so that we couldn't find the |
|
2614 # file. We try harder to rebuild the subject's metadata |
|
2615 # if it's the first time we fail (count == 0). |
|
2616 if count == 0 and e.errno == errno.ENOENT: |
|
2617 self.__rebuild_subj_root() |
|
2618 try: |
|
2619 res.append(load_cert(pth)) |
|
2620 except EnvironmentError as e: |
|
2621 if e.errno != errno.ENOENT: |
|
2622 raise |
|
2623 |
2562 t = api_errors._convert_error(e, |
2624 t = api_errors._convert_error(e, |
2563 [errno.ENOENT]) |
2625 [errno.ENOENT]) |
2564 if t: |
2626 if t: |
2565 raise t |
2627 raise t |
2566 res.extend(self.__issuers.get(name_hsh, [])) |
2628 res.extend(self.__issuers.get(name_hsh, [])) |
2576 # CA certs approved for this publisher are stored by hash to |
2638 # CA certs approved for this publisher are stored by hash to |
2577 # prevent the later substitution or confusion over what certs |
2639 # prevent the later substitution or confusion over what certs |
2578 # have or have not been approved. |
2640 # have or have not been approved. |
2579 for h in set(self.approved_ca_certs): |
2641 for h in set(self.approved_ca_certs): |
2580 c = self.get_cert_by_hash(h, verify_hash=True) |
2642 c = self.get_cert_by_hash(h, verify_hash=True) |
2581 s = c.get_subject().as_hash() |
2643 s = hashlib.sha1(misc.force_bytes( |
|
2644 c.subject)).hexdigest() |
2582 self.ca_dict.setdefault(s, []) |
2645 self.ca_dict.setdefault(s, []) |
2583 self.ca_dict[s].append(c) |
2646 self.ca_dict[s].append(c) |
2584 return self.ca_dict |
2647 return self.ca_dict |
2585 |
2648 |
2586 def update_props(self, set_props=EmptyI, add_prop_values=EmptyDict, |
2649 def update_props(self, set_props=EmptyI, add_prop_values=EmptyDict, |
2650 |
2713 |
2651 def __format_safe_read_crl(self, pth): |
2714 def __format_safe_read_crl(self, pth): |
2652 """CRLs seem to frequently come in DER format, so try reading |
2715 """CRLs seem to frequently come in DER format, so try reading |
2653 the CRL using both of the formats before giving up.""" |
2716 the CRL using both of the formats before giving up.""" |
2654 |
2717 |
|
2718 with open(pth, "rb") as f: |
|
2719 raw = f.read() |
|
2720 |
2655 try: |
2721 try: |
2656 return m2.X509.load_crl(pth) |
2722 return x509.load_pem_x509_crl(raw, default_backend()) |
2657 except m2.X509.X509Error: |
2723 except ValueError: |
2658 try: |
2724 try: |
2659 return m2.X509.load_crl(pth, |
2725 return x509.load_der_x509_crl(raw, |
2660 format=m2.X509.FORMAT_DER) |
2726 default_backend()) |
2661 except m2.X509.X509Error: |
2727 except ValueError: |
2662 raise api_errors.BadFileFormat(_("The CRL file " |
2728 raise api_errors.BadFileFormat(_("The CRL file " |
2663 "{0} is not in a recognized " |
2729 "{0} is not in a recognized " |
2664 "format.").format(pth)) |
2730 "format.").format(pth)) |
2665 |
2731 |
2666 def __get_crl(self, uri): |
2732 def __get_crl(self, uri): |
2763 portable.remove(tmp_pth) |
2824 portable.remove(tmp_pth) |
2764 except EnvironmentError: |
2825 except EnvironmentError: |
2765 pass |
2826 pass |
2766 return ncrl |
2827 return ncrl |
2767 |
2828 |
2768 def __check_crls(self, cert, ca_dict): |
2829 |
2769 """Determines whether the certificate has been revoked by its |
2830 def __verify_x509_signature(self, c, key): |
2770 CRL. |
2831 """Verify the signature of a certificate or CRL 'c' against a |
|
2832 provided public key 'key'.""" |
|
2833 |
|
2834 verifier = key.verifier( |
|
2835 c.signature, padding.PKCS1v15(), |
|
2836 c.signature_hash_algorithm) |
|
2837 |
|
2838 if isinstance(c, x509.Certificate): |
|
2839 data = c.tbs_certificate_bytes |
|
2840 elif isinstance(c, x509.CertificateRevocationList): |
|
2841 data = c.tbs_certlist_bytes |
|
2842 else: |
|
2843 raise AssertionError("Invalid x509 object for " |
|
2844 "signature verification: {0}".format(type(c))) |
|
2845 |
|
2846 verifier.update(data) |
|
2847 try: |
|
2848 verifier.verify() |
|
2849 return True |
|
2850 except Exception: |
|
2851 return False |
|
2852 |
|
2853 def __check_crl(self, cert, ca_dict, crl_uri): |
|
2854 """Determines whether the certificate has been revoked by the |
|
2855 CRL located at 'crl_uri'. |
2771 |
2856 |
2772 The 'cert' parameter is the certificate to check for revocation. |
2857 The 'cert' parameter is the certificate to check for revocation. |
2773 |
2858 |
2774 The 'ca_dict' is a dictionary which maps subject hashes to |
2859 The 'ca_dict' is a dictionary which maps subject hashes to |
2775 certs treated as trust anchors.""" |
2860 certs treated as trust anchors.""" |
2776 |
2861 |
2777 # If the certificate doesn't have a CRL location listed, treat |
2862 crl = self.__get_crl(crl_uri) |
2778 # it as valid. |
2863 |
2779 try: |
|
2780 ext = cert.get_ext("crlDistributionPoints") |
|
2781 except LookupError as e: |
|
2782 return True |
|
2783 uri = ext.get_value() |
|
2784 crl = self.__get_crl(uri) |
|
2785 # If we couldn't retrieve a CRL from the distribution point |
2864 # If we couldn't retrieve a CRL from the distribution point |
2786 # and no CRL is cached on disk, assume the cert has not been |
2865 # and no CRL is cached on disk, assume the cert has not been |
2787 # revoked. It's possible that this should be an image or |
2866 # revoked. It's possible that this should be an image or |
2788 # publisher setting in the future. |
2867 # publisher setting in the future. |
2789 if not crl: |
2868 if not crl: |
2790 return True |
2869 return True |
2791 |
2870 |
2792 # A CRL has been found, now it needs to be validated like |
2871 # A CRL has been found, now it needs to be validated like |
2793 # a certificate is. |
2872 # a certificate is. |
2794 verified_crl = False |
2873 verified_crl = False |
2795 crl_issuer = crl.get_issuer() |
2874 crl_issuer = crl.issuer |
2796 tas = ca_dict.get(crl_issuer.as_hash(), []) |
2875 tas = ca_dict.get(hashlib.sha1(misc.force_bytes( |
|
2876 crl_issuer)).hexdigest(), []) |
2797 for t in tas: |
2877 for t in tas: |
2798 try: |
2878 try: |
2799 if crl.verify(t.get_pubkey()): |
2879 if self.__verify_x509_signature(crl, |
|
2880 t.public_key()): |
2800 # If t isn't approved for signing crls, |
2881 # If t isn't approved for signing crls, |
2801 # the exception __check_extensions |
2882 # the exception __check_extensions |
2802 # raises will take the code to the |
2883 # raises will take the code to the |
2803 # except below. |
2884 # except below. |
2804 self.__check_extensions(t, |
2885 self.__check_extensions(t, |
2819 else: |
2901 else: |
2820 verified_crl = True |
2902 verified_crl = True |
2821 break |
2903 break |
2822 if not verified_crl: |
2904 if not verified_crl: |
2823 return True |
2905 return True |
|
2906 |
2824 # For a certificate to be revoked, its CRL must be validated |
2907 # For a certificate to be revoked, its CRL must be validated |
2825 # and revoked the certificate. |
2908 # and revoked the certificate. |
2826 rev = crl.is_revoked(cert) |
2909 |
2827 if rev: |
2910 assert crl.issuer == cert.issuer |
2828 raise api_errors.RevokedCertificate(cert, rev[1]) |
2911 for rev in crl: |
|
2912 if rev.serial_number != cert.serial: |
|
2913 continue |
|
2914 try: |
|
2915 reason = rev.extensions.get_extension_for_oid( |
|
2916 x509.OID_CRL_REASON).value |
|
2917 except x509.ExtensionNotFound: |
|
2918 reason = None |
|
2919 raise api_errors.RevokedCertificate(cert, reason) |
|
2920 |
|
2921 def __check_crls(self, cert, ca_dict): |
|
2922 """Determines whether the certificate has been revoked by one of |
|
2923 its CRLs. |
|
2924 |
|
2925 The 'cert' parameter is the certificate to check for revocation. |
|
2926 |
|
2927 The 'ca_dict' is a dictionary which maps subject hashes to |
|
2928 certs treated as trust anchors.""" |
|
2929 |
|
2930 # If the certificate doesn't have a CRL location listed, treat |
|
2931 # it as valid. |
|
2932 |
|
2933 # The CRLs to be retrieved are stored in the |
|
2934 # CRLDistributionPoints extensions which is structured like |
|
2935 # this: |
|
2936 # |
|
2937 # CRLDitsributionPoints = [ |
|
2938 # CRLDistributionPoint = [ |
|
2939 # union { |
|
2940 # full_name = [ GeneralName, ... ] |
|
2941 # relative_name = [ GeneralName, ... ] |
|
2942 # }, ... ] |
|
2943 # , ... ] |
|
2944 # |
|
2945 # Relative names are a feature in X509 certs which allow to |
|
2946 # specify a location relative to another certificate. We are not |
|
2947 # supporting this and I'm not sure anybody is using this for |
|
2948 # CRLs. |
|
2949 # Full names are absolute locations but can be in different |
|
2950 # formats (refer to RFC5280) but in general only the URI type is |
|
2951 # used for CRLs. So this is the only thing we support here. |
|
2952 |
|
2953 try: |
|
2954 dps = cert.extensions.get_extension_for_oid( |
|
2955 x509.oid.ExtensionOID.CRL_DISTRIBUTION_POINTS).value |
|
2956 except x509.ExtensionNotFound: |
|
2957 return |
|
2958 |
|
2959 for dp in dps: |
|
2960 if not dp.full_name: |
|
2961 # we don't support relative names |
|
2962 continue |
|
2963 for uri in dp.full_name: |
|
2964 if not isinstance(uri, |
|
2965 x509.UniformResourceIdentifier): |
|
2966 # we only support URIs |
|
2967 continue |
|
2968 self.__check_crl(cert, ca_dict, str(uri.value)) |
2829 |
2969 |
2830 def __check_revocation(self, cert, ca_dict, use_crls): |
2970 def __check_revocation(self, cert, ca_dict, use_crls): |
2831 hsh = self.__hash_cert(cert) |
2971 hsh = self.__hash_cert(cert) |
2832 if hsh in self.revoked_ca_certs: |
2972 if hsh in self.revoked_ca_certs: |
2833 raise api_errors.RevokedCertificate(cert, |
2973 raise api_errors.RevokedCertificate(cert, |
2837 |
2977 |
2838 def __check_extensions(self, cert, usages, cur_pathlen): |
2978 def __check_extensions(self, cert, usages, cur_pathlen): |
2839 """Check whether the critical extensions in this certificate |
2979 """Check whether the critical extensions in this certificate |
2840 are supported and allow the provided use(s).""" |
2980 are supported and allow the provided use(s).""" |
2841 |
2981 |
|
2982 try: |
|
2983 exts = cert.extensions |
|
2984 except (ValueError, x509.UnsupportedExtension) as e: |
|
2985 raise api_errors.InvalidCertificateExtensions( |
|
2986 cert, e) |
|
2987 |
2842 def check_values(vs): |
2988 def check_values(vs): |
2843 for v in vs: |
2989 for v in vs: |
2844 if v in supported_vs: |
2990 if v in supported_vs: |
2845 continue |
2991 continue |
2846 if v.startswith("PATHLEN:") and \ |
2992 # If there is only one extension value, it must |
2847 "PATHLEN:" in supported_vs: |
2993 # be the problematic one. Otherwise, we also |
2848 try: |
2994 # output the first unsupported value as the |
2849 cert_pathlen = int(v[len("PATHLEN:"):]) |
2995 # problematic value following extension value. |
2850 except ValueError as e: |
|
2851 raise api_errors.UnsupportedExtensionValue(cert, ext, v) |
|
2852 if cur_pathlen > cert_pathlen: |
|
2853 raise api_errors.PathlenTooShort(cert, cur_pathlen, cert_pathlen) |
|
2854 continue |
|
2855 if len(vs) < 2: |
2996 if len(vs) < 2: |
2856 raise api_errors.UnsupportedExtensionValue(cert, ext) |
2997 raise api_errors.UnsupportedExtensionValue( |
2857 else: |
2998 cert, ext, ", ".join(vs)) |
2858 raise api_errors.UnsupportedExtensionValue(cert, ext, v) |
2999 raise api_errors.UnsupportedExtensionValue( |
2859 |
3000 cert, ext, ", ".join(vs), v) |
2860 |
3001 |
2861 for i in range(0, cert.get_ext_count()): |
3002 for ext in exts: |
2862 ext = cert.get_ext_at(i) |
3003 etype = type(ext.value) |
2863 name = ext.get_name() |
3004 if etype in SUPPORTED_EXTENSION_VALUES: |
2864 if name == "UNDEF": |
3005 supported_vs = SUPPORTED_EXTENSION_VALUES[etype] |
2865 continue |
3006 keys = EXTENSIONS_VALUES[etype] |
2866 v = ext.get_value().upper() |
3007 if etype == x509.BasicConstraints: |
2867 # Check whether the extension name is recognized. |
3008 pathlen = ext.value.path_length |
2868 if name in SUPPORTED_EXTENSION_VALUES: |
3009 if pathlen is not None and \ |
2869 supported_vs = \ |
3010 cur_pathlen > pathlen: |
2870 SUPPORTED_EXTENSION_VALUES[name] |
3011 raise api_errors.PathlenTooShort(cert, |
2871 vs = [s.strip() for s in v.split(",")] |
3012 cur_pathlen, pathlen) |
|
3013 elif etype == x509.KeyUsage: |
|
3014 keys = list(EXTENSIONS_VALUES[etype]) |
|
3015 if not getattr(ext.value, |
|
3016 "key_agreement"): |
|
3017 # Cryptography error: |
|
3018 # encipher_only/decipher_only is |
|
3019 # undefined unless key_agreement |
|
3020 # is true |
|
3021 keys.remove("encipher_only") |
|
3022 keys.remove("decipher_only") |
|
3023 vs = [ |
|
3024 key |
|
3025 for key in keys |
|
3026 if getattr(ext.value, key) |
|
3027 ] |
2872 # Check whether the values for the extension are |
3028 # Check whether the values for the extension are |
2873 # recognized. |
3029 # recognized. |
2874 check_values(vs) |
3030 check_values(vs) |
2875 uses = usages.get(name, []) |
|
2876 if isinstance(uses, six.string_types): |
|
2877 uses = [uses] |
|
2878 # For each use, check to see whether it's |
3031 # For each use, check to see whether it's |
2879 # permitted by the certificate's extension |
3032 # permitted by the certificate's extension |
2880 # values. |
3033 # values. |
2881 for u in uses: |
3034 if etype not in usages: |
|
3035 continue |
|
3036 for u in usages[etype]: |
2882 if u not in vs: |
3037 if u not in vs: |
2883 raise api_errors.InappropriateCertificateUse(cert, ext, u) |
3038 raise api_errors.InappropriateCertificateUse( |
|
3039 cert, ext, u, ", ".join(vs)) |
2884 # If the extension name is unrecognized and critical, |
3040 # If the extension name is unrecognized and critical, |
2885 # then the chain cannot be verified. |
3041 # then the chain cannot be verified. |
2886 elif ext.get_critical(): |
3042 elif ext.critical: |
2887 raise api_errors.UnsupportedCriticalExtension( |
3043 raise api_errors.UnsupportedCriticalExtension( |
2888 cert, ext) |
3044 cert, ext) |
2889 |
3045 |
2890 def verify_chain(self, cert, ca_dict, cur_pathlen, use_crls, |
3046 def verify_chain(self, cert, ca_dict, cur_pathlen, use_crls, |
2891 required_names=None, usages=None): |
3047 required_names=None, usages=None): |
2952 # If this certificate's CN is in the set of required |
3108 # If this certificate's CN is in the set of required |
2953 # names, remove it. |
3109 # names, remove it. |
2954 discard_names(cert, required_names) |
3110 discard_names(cert, required_names) |
2955 |
3111 |
2956 # Find the certificate that issued this certificate. |
3112 # Find the certificate that issued this certificate. |
2957 issuer = cert.get_issuer() |
3113 issuer = cert.issuer |
2958 issuer_hash = issuer.as_hash() |
3114 issuer_hash = hashlib.sha1(misc.force_bytes( |
|
3115 issuer)).hexdigest() |
2959 |
3116 |
2960 # See whether this certificate was issued by any of the |
3117 # See whether this certificate was issued by any of the |
2961 # given trust anchors. |
3118 # given trust anchors. |
2962 for c in ca_dict.get(issuer_hash, []): |
3119 for c in ca_dict.get(issuer_hash, []): |
2963 if cert.verify(c.get_pubkey()): |
3120 if self.__verify_x509_signature(cert, |
|
3121 c.public_key()): |
2964 verified = True |
3122 verified = True |
2965 # Remove any required names found in the |
3123 # Remove any required names found in the |
2966 # trust anchor. |
3124 # trust anchor. |
2967 discard_names(c, required_names) |
3125 discard_names(c, required_names) |
2968 # If there are more names to check for |
3126 # If there are more names to check for |