Exemple #1
0
 def _decode_hook(self):
     self._mappings = []
     if self.asn1 is not None:
         for mapping in self.asn1:
             self._mappings.append(
                 self._PolicyMapping(issuer_policy=OID.from_asn1(
                     mapping["issuerDomainPolicy"]),
                                     subject_policy=OID.from_asn1(
                                         mapping["subjectDomainPolicy"])))
Exemple #2
0
    def from_subject_pubkey_info(cls, pk_alg, params_asn1, pubkey_data):
        params = ASN1Tools.safe_decode(params_asn1, asn1_spec=ECParameters())

        accessible_parameters = {}
        if params.asn1 is not None:
            accessible_parameters["curve_source"] = params.asn1.getName()
            if accessible_parameters["curve_source"] == "namedCurve":
                # Named curve
                curve_oid = OID.from_asn1(params.asn1.getComponent())
                curve = CurveDB().instantiate(oid=curve_oid)
                accessible_parameters.update({
                    "curve_oid": curve_oid,
                    "curve": curve,
                })
            elif accessible_parameters["curve_source"] == "specifiedCurve":
                # Explicit curve or implicit curve
                curve = EllipticCurve.from_asn1(params.asn1.getComponent())
                accessible_parameters.update({
                    "curve": curve,
                })
            else:
                # Implicit curve
                pass

        if accessible_parameters.get("curve") is not None:
            pk_point = curve.decode_point(pubkey_data)
            accessible_parameters.update({
                "x": pk_point.x,
                "y": pk_point.y,
            })
        else:
            pk_point = None

        return cls(accessible_parameters=accessible_parameters,
                   decoding_details=[params, pk_point])
Exemple #3
0
 def _decode_hook(self):
     self._methods = []
     if self.asn1 is not None:
         for item in self.asn1:
             oid = OID.from_asn1(item["accessMethod"])
             location = item["accessLocation"]
             self._methods.append((oid, location))
 def from_asn1(cls, asn1):
     rdn_elements = []
     for attribute_type_and_value in asn1:
         attribute_type_oid = OID.from_asn1(attribute_type_and_value[0])
         attribute_value = bytes(attribute_type_and_value[1])
         rdn_elements.append((attribute_type_oid, attribute_value))
     return cls(rdn_elements)
Exemple #5
0
 def signature_algorithm(self):
     algorithm_oid = OID.from_asn1(
         self.asn1["signatureAlgorithm"]["algorithm"])
     sig_alg = SignatureAlgorithms.lookup("oid", algorithm_oid)
     if sig_alg is None:
         raise UnknownAlgorithmException("Unknown signature OID %s." %
                                         (algorithm_oid))
     return sig_alg
Exemple #6
0
	def _get_extensions(self):
		result = [ ]
		if self.asn1["tbsCertificate"]["extensions"] is not None:
			for extension in self.asn1["tbsCertificate"]["extensions"]:
				oid = OID.from_asn1(extension["extnID"])
				critical = bool(extension["critical"])
				value = bytes(extension["extnValue"])
				result.append(X509ExtensionRegistry.create(oid, critical, value))
		return X509Extensions(result)
Exemple #7
0
 def _load_db_data():
     json_data = JSONTools.load_internal("x509sak.data.ecc", "curves.json")
     result = {
         OID.from_str(oid): parameters
         for (oid, parameters) in json_data.items()
     }
     for (oid, parameters) in result.items():
         parameters["oid"] = oid
     return result
Exemple #8
0
 def _decode_hook(self):
     self._description = []
     if self.asn1 is not None:
         for access_description in self.asn1:
             self._description.append(
                 self._AccessDescription(
                     method=OID.from_asn1(
                         access_description["accessMethod"]),
                     location=ASN1GeneralNameWrapper.from_asn1(
                         access_description["accessLocation"])))
Exemple #9
0
 def _decode_hook(self):
     self._policies = []
     if self.asn1 is None:
         return
     for item in self.asn1:
         policy_oid = OID.from_asn1(item["policyIdentifier"])
         qualifiers = []
         for qualifier in item["policyQualifiers"]:
             qualifier_oid = OID.from_asn1(qualifier["policyQualifierId"])
             qualifier_data = bytes(qualifier["qualifier"])
             qualifier = self._CertificatePolicyQualifier(
                 oid=qualifier_oid,
                 qualifier_data=qualifier_data,
                 decoded_qualifier=self.decode_qualifier(
                     qualifier_oid, qualifier_data))
             qualifiers.append(qualifier)
         policy = self._CertificatePolicy(oid=policy_oid,
                                          qualifiers=tuple(qualifiers))
         self._policies.append(policy)
Exemple #10
0
 def _decode_hook(self):
     self._attributes = []
     if self.asn1 is not None:
         for attribute in self.asn1:
             self._attributes.append(
                 self._Attribute(attribute_type=OID.from_asn1(
                     attribute["type"]),
                                 values=[
                                     ASN1Tools.safe_decode(value)
                                     for value in attribute["values"]
                                 ]))
Exemple #11
0
    def from_asn1(cls, asn1):
        constructor_arguments = {}
        if asn1["hashAlgorithm"].hasValue():
            constructor_arguments["hash_algorithm_oid"] = OID.from_asn1(
                asn1["hashAlgorithm"]["algorithm"])
        else:
            # Default for RSASSA-PSS is SHA-1
            constructor_arguments[
                "hash_algorithm_oid"] = OIDDB.HashFunctions.inverse("sha1")

        if asn1["maskGenAlgorithm"].hasValue():
            constructor_arguments["mask_algorithm_oid"] = OID.from_asn1(
                asn1["maskGenAlgorithm"]["algorithm"])
            (decoded_mask_parameters, tail) = pyasn1.codec.der.decoder.decode(
                asn1["maskGenAlgorithm"]["parameters"],
                asn1Spec=ASN1Models.HashAlgorithm())
            constructor_arguments["mask_hash_algorithm_oid"] = OID.from_asn1(
                decoded_mask_parameters["algorithm"])
        else:
            # Default for RSASSA-PSS is mgf1 with SHA-1
            constructor_arguments[
                "mask_algorithm_oid"] = OIDDB.RSAPSSMaskGenerationAlgorithm.inverse(
                    "mgf1")
            constructor_arguments[
                "mask_hash_algorithm_oid"] = OIDDB.HashFunctions.inverse(
                    "sha1")

        if asn1["saltLength"].hasValue():
            constructor_arguments["salt_length"] = int(asn1["saltLength"])
        else:
            constructor_arguments["salt_length"] = 20

        if asn1["trailerField"].hasValue():
            constructor_arguments["trailer_field"] = int(asn1["trailerField"])
        else:
            constructor_arguments["trailer_field"] = 1

        return cls(**constructor_arguments)
Exemple #12
0
    def _post_decode_hook(self):
        if self.asn1["parameters"] is None:
            raise InvalidInputException(
                "ECC private key does not contain curve OID. Cannot proceed.")
        if self.asn1["publicKey"] is None:
            raise InvalidInputException(
                "ECC private key does not contain public key. Cannot proceed.")

        curve_oid = OID.from_asn1(self.asn1["parameters"])
        self._curve = CurveDB().instantiate(oid=curve_oid)

        self._d = int.from_bytes(self.asn1["privateKey"], byteorder="big")
        (self._x, self._y) = ECCTools.decode_enc_pubkey(
            ASN1Tools.bitstring2bytes(self.asn1["publicKey"]))
Exemple #13
0
    def _post_decode_hook(self):
        alg_oid = OID.from_asn1(self.asn1["algorithm"]["algorithm"])
        self._pk_alg = PublicKeyAlgorithms.lookup("oid", alg_oid)
        if self._pk_alg is None:
            self._key_decoding_error = "Unable to determine public key algorithm for OID %s." % (
                alg_oid)
            return

        if self._pk_alg not in self._HANDLERS_BY_PK_ALG:
            self._key_decoding_error = "Unable to determine public key handler for public key algorithm %s." % (
                self._pk_alg.name)
            return

        handler_class = self._HANDLERS_BY_PK_ALG[self._pk_alg]
        key_data = ASN1Tools.bitstring2bytes(self.asn1["subjectPublicKey"])
        self._key = handler_class.from_subject_pubkey_info(
            self._pk_alg, self.asn1["algorithm"]["parameters"], key_data)
        self._key_decoding_error = None
Exemple #14
0
    def _post_decode_hook(self):
        if self.asn1["privateKeyAlgorithm"]["algorithm"] is None:
            raise InvalidInputException(
                "EdDSA private key does not contain curve OID. Cannot proceed."
            )

        curve_oid = OID.from_asn1(
            self.asn1["privateKeyAlgorithm"]["algorithm"])
        pk_alg = PublicKeyAlgorithms.lookup("oid", curve_oid)
        self._curve = CurveDB().instantiate(oid=curve_oid)
        self._prehash = pk_alg.value.fixed_params["prehash"]
        private_key = bytes(self.asn1["privateKey"])
        if (private_key[0] != 0x04) or (private_key[1] !=
                                        self.curve.element_octet_cnt):
            raise InvalidInputException(
                "EdDSA private key does start with 04 %02x, but with %02x %02x."
                %
                (self.curve.element_octet_cnt, private_key[0], private_key[1]))
        if len(private_key) != self.curve.element_octet_cnt + 2:
            raise InvalidInputException(
                "EdDSA private key length expected to be %d octets, but was %d octets."
                % (self.curve.element_octet_cnt + 2, len(private_key[0])))
        self._priv = private_key[2:]
Exemple #15
0
 def _decode_hook(self):
     if self.asn1 is not None:
         self._oids = [OID.from_str(str(oid)) for oid in self.asn1]
     else:
         self._oids = []
Exemple #16
0
	def extension_oid_abbreviation(cls, oid):
		if oid is None:
			return None
		return cls._Exported_Extension_OIDs.get(OID.from_str(oid))
Exemple #17
0
 def registered_id(self):
     assert (self.name == "registeredID")
     if self._cached is None:
         self._cached = OID.from_asn1(self.asn1_value)
     return self._cached
Exemple #18
0
 def signature_alg_oid(self):
     signature_alg_oid = OID.from_str(
         str(self.asn1["signatureAlgorithm"]["algorithm"]))
     return signature_alg_oid
Exemple #19
0
    def from_asn1(cls, asn1):
        """Decode explicitly encoded elliptic curve domain parameters, given as a Sequence (SpecifiedECDomain)."""
        version = int(asn1["version"])
        if version != 1:
            raise InvalidInputException(
                "Attempted to decode the excplicit EC domain and saw unknown version %d."
                % (version))

        field_type = OID.from_asn1(asn1["fieldID"]["fieldType"])
        field_type_id = OIDDB.ECFieldType.get(field_type)
        if field_type_id is None:
            raise InvalidInputException(
                "Encountered explicit EC domain parameters in unknown field with OID %s."
                % (str(field_type)))

        domain_parameters = {
            "a": int.from_bytes(bytes(asn1["curve"]["a"]), byteorder="big"),
            "b": int.from_bytes(bytes(asn1["curve"]["b"]), byteorder="big"),
            "n": int(asn1["order"]),
        }
        if asn1["cofactor"].hasValue():
            domain_parameters["h"] = int(asn1["cofactor"])
        base_point = bytes(asn1["base"])
        if field_type_id == "prime-field":
            (field_params, tail) = pyasn1.codec.der.decoder.decode(
                bytes(asn1["fieldID"]["parameters"]),
                asn1Spec=ECFieldParametersPrimeField())
            if len(tail) != 0:
                raise InvalidInputException(
                    "Attempted to decode the excplicit EC domain and encountered %d bytes of trailing data of the prime basis Integer."
                    % (len(tail)))

            domain_parameters.update({
                "p": int(field_params),
            })
            return cls.get_class_for_curvetype("prime").instantiate(
                domain_parameters, base_point)
        elif field_type_id == "characteristic-two-field":
            (field_params, tail) = pyasn1.codec.der.decoder.decode(
                bytes(asn1["fieldID"]["parameters"]),
                asn1Spec=ECFieldParametersCharacteristicTwoField())
            if len(tail) != 0:
                raise InvalidInputException(
                    "Attempted to decode the excplicit EC domain and encountered %d bytes of trailing data of the characteristic two field Sequence."
                    % (len(tail)))

            basis_type = OID.from_asn1(field_params["basis"])
            basis_type_id = OIDDB.ECTwoFieldBasistype.get(basis_type)
            if basis_type_id is None:
                raise InvalidInputException(
                    "Unknown two-field basis type with OID %s found in public key."
                    % (str(basis_type)))

            # Field width is common to all two-fields
            domain_parameters.update({
                "m": int(field_params["m"]),
                "basis": basis_type_id,
            })

            if basis_type_id == "gnBasis":
                raise InvalidInputException(
                    "Binary field explicit domain parameters with Gaussian polynomial basis is not implemented."
                )
            elif basis_type_id == "tpBasis":
                (params, tail) = ASN1Tools.redecode(
                    field_params["parameters"],
                    ECFieldParametersCharacteristicTwoFieldTrinomial())
                if len(tail) != 0:
                    raise InvalidInputException(
                        "Attempted to decode the excplicit EC domain and encountered %d bytes of trailing data of the characteristic two field trinomial basis."
                        % (len(tail)))
                poly = [domain_parameters["m"], int(params), 0]
            elif basis_type_id == "ppBasis":
                (params, tail) = ASN1Tools.redecode(
                    field_params["parameters"],
                    ECFieldParametersCharacteristicTwoFieldPentanomial())
                if len(tail) != 0:
                    raise InvalidInputException(
                        "Attempted to decode the excplicit EC domain and encountered %d bytes of trailing data of the characteristic two field pentanomial basis."
                        % (len(tail)))
                poly = [
                    domain_parameters["m"],
                    int(params["k1"]),
                    int(params["k2"]),
                    int(params["k3"]), 0
                ]
            else:
                raise NotImplementedError("Binary field basis", basis_type_id)
            domain_parameters.update({
                "m": int(field_params["m"]),
                "poly": poly,
            })
            return cls.get_class_for_curvetype("binary").instantiate(
                domain_parameters, base_point)
        else:
            raise NotImplementedError(
                "Explicit EC domain parameter encoding for field type \"%s\" is not implemented."
                % (field_type_id))
    def _analyze_certificate_general_issues(self, certificate):
        judgements = SecurityJudgements()
        if certificate.version != 3:
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_Body_Version_Not3,
                "Certificate version is v%d, usually would expect a v3 certificate."
                % (certificate.version),
                commonness=Commonness.HIGHLY_UNUSUAL)

        if certificate.serial < 0:
            standard = RFCReference(
                rfcno=5280,
                sect="4.1.2.2",
                verb="MUST",
                text=
                "The serial number MUST be a positive integer assigned by the CA to each certificate."
            )
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_Body_SerialNumber_BasicChecks_Negative,
                "Certificate serial number is a negative value.",
                compatibility=Compatibility.STANDARDS_DEVIATION,
                standard=standard)
        elif certificate.serial == 0:
            standard = RFCReference(
                rfcno=5280,
                sect="4.1.2.2",
                verb="MUST",
                text=
                "The serial number MUST be a positive integer assigned by the CA to each certificate."
            )
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_Body_SerialNumber_BasicChecks_Zero,
                "Certificate serial number is zero.",
                compatibility=Compatibility.STANDARDS_DEVIATION,
                standard=standard)
        elif certificate.serial >= (2**(8 * 20)):
            standard = RFCReference(
                rfcno=5280,
                sect="4.1.2.2",
                verb="MUST",
                text=
                "Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
            )
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_Body_SerialNumber_BasicChecks_Large,
                "Certificate serial number is too large.",
                compatibility=Compatibility.STANDARDS_DEVIATION,
                standard=standard)

        if "non_der" in certificate.asn1_details.flags:
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_Malformed_NonDEREncoding,
                "Certificate uses invalid DER encoding. Original certificate is %d bytes; DER would be %d bytes."
                % (len(certificate.asn1_details.original_der),
                   len(certificate.asn1_details.encoded_der)),
                compatibility=Compatibility.STANDARDS_DEVIATION)

        if "trailing_data" in certificate.asn1_details.flags:
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_TrailingData,
                "Certificate contains %d bytes of trailing data." %
                (len(certificate.asn1_details.tail)),
                compatibility=Compatibility.STANDARDS_DEVIATION)

        standard = RFCReference(
            rfcno=5280,
            sect=["4.1.1.2", "4.1.2.3"],
            verb="MUST",
            text=
            "This field MUST contain the same algorithm identifier as the signature field in the sequence tbsCertificate (Section 4.1.2.3)."
        )
        oid_header = OID.from_asn1(
            certificate.asn1["tbsCertificate"]["signature"]["algorithm"])
        oid_sig = OID.from_asn1(
            certificate.asn1["signatureAlgorithm"]["algorithm"])
        if oid_header != oid_sig:
            name_header = OIDDB.SignatureAlgorithms.get(
                oid_header, str(oid_header))
            name_sig = OIDDB.SignatureAlgorithms.get(oid_sig, str(oid_sig))
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_Signature_Function_BodyMismatch,
                "Certificate indicates signature algorithm %s in header section and %s in signature section."
                % (name_header, name_sig),
                compatibility=Compatibility.STANDARDS_DEVIATION,
                standard=standard)
        else:
            # OIDs might be same, but parameters could differ (e.g., for RSA-PSS)
            header_hasvalue = certificate.asn1["tbsCertificate"]["signature"][
                "parameters"].hasValue()
            signature_hasvalue = certificate.asn1["signatureAlgorithm"][
                "parameters"].hasValue()
            if header_hasvalue and signature_hasvalue:
                name_header = OIDDB.SignatureAlgorithms.get(
                    oid_header, str(oid_header))
                parameters_header = bytes(certificate.asn1["tbsCertificate"]
                                          ["signature"]["parameters"])
                parameters_signature = bytes(
                    certificate.asn1["signatureAlgorithm"]["parameters"])
                if parameters_header != parameters_signature:
                    judgements += SecurityJudgement(
                        JudgementCode.X509Cert_Signature_Function_BodyMismatch,
                        "Certificate indicates same signature algorithm in both header section and signature section (%s), but parameterization of each differ."
                        % (name_header),
                        compatibility=Compatibility.STANDARDS_DEVIATION,
                        standard=standard)
            elif header_hasvalue != signature_hasvalue:
                judgements += SecurityJudgement(
                    JudgementCode.X509Cert_Signature_Function_BodyMismatch,
                    "Certificate indicates same signature algorithm in both header section and signature section, but header %s while signature section %s."
                    % ("has parameters"
                       if header_hasvalue else "has no parameters",
                       "does" if signature_hasvalue else "does not"),
                    compatibility=Compatibility.STANDARDS_DEVIATION,
                    standard=standard)

        return judgements
Exemple #21
0
class ActionTestcaseGen(BaseAction):
    _EXPECT_PRESENT_CODEPOINT_OID = OID.from_str("1.13.99.127.41")
    _TCDefinition = collections.namedtuple(
        "TCDefinition", ["full_name", "filename", "expect_present"])

    def __init__(self, cmdname, args):
        BaseAction.__init__(self, cmdname, args)

        sys.setrecursionlimit(10000)
        self._cg = CertGenerator.instantiate(self._args.tcname + ".ader")
        if self._args.list_parameters:
            for (name, values) in sorted(self._cg.parameters):
                print("%-30s %s" % (name, ", ".join(sorted(values))))
            sys.exit(0)

        template_parameters = {}
        for parameter in self._args.parameter:
            (key, value) = parameter.split("=", maxsplit=1)
            if value == "*":
                template_parameters[key] = self._cg.get_choices(key)
            else:
                template_parameters[key] = [value]

        for (name, values) in self._cg.parameters:
            if name not in template_parameters:
                template_parameters[name] = values

        with contextlib.suppress(FileExistsError):
            os.makedirs(self._args.output_dir)

        template_parameters = list(template_parameters.items())
        keys = [key for (key, values) in template_parameters]
        values = [values for (key, values) in template_parameters]
        self._tcs = []
        for concrete_values in itertools.product(*values):
            concrete_values = dict(zip(keys, concrete_values))
            try:
                self._render(concrete_values)
            except subprocess.CalledProcessError as e:
                print("Failed: %s (%s)" % (str(concrete_values), str(e)))

        self._tcs.sort()
        self._print_tcs()

    @staticmethod
    def testcase_codepoint_string(codepoints):
        if len(codepoints) == 1:
            return "\"%s\"" % (codepoints[0])
        else:
            return "[ " + ", ".join("\"%s\"" % (codepoint)
                                    for codepoint in codepoints) + " ]"

    def _print_tcs(self):
        with open(self._args.output_dir + "/tcs.txt", "w") as f:
            print("# " + ("=" * 70) + " Begin of %s " % (self._args.tcname) +
                  ("=" * 70),
                  file=f)
            for tc in self._tcs:
                print("\tdef %s(self):" % (tc.full_name), file=f)
                print(
                    "\t\tself._test_examine_x509test_resultcode(\"%s\", expect_present = %s)"
                    % (tc.filename,
                       self.testcase_codepoint_string(tc.expect_present)),
                    file=f)
                print(file=f)
            print("# " + ("=" * 70) + " End of %s " % (self._args.tcname) +
                  ("=" * 70),
                  file=f)

    def _extract_codepoints(self, filename_prefix, pem_file):
        x509cert = X509Certificate.from_pem_data(pem_file)[0]
        present_codepoints = [
            rdn.get_value(self._EXPECT_PRESENT_CODEPOINT_OID).printable_value
            for rdn in x509cert.subject.get_all(
                self._EXPECT_PRESENT_CODEPOINT_OID)
        ]
        present_codepoints += [
            rdn.get_value(self._EXPECT_PRESENT_CODEPOINT_OID).printable_value
            for rdn in x509cert.issuer.get_all(
                self._EXPECT_PRESENT_CODEPOINT_OID)
        ]

        codepoints = []
        for codepoint_name in present_codepoints:
            if "#" in codepoint_name:
                continue
            try:
                getattr(JudgementCode, codepoint_name)
            except AttributeError:
                print("No such codepoint: %s (in %s)" %
                      (codepoint_name, filename_prefix))
                continue
            codepoints.append(codepoint_name)
        return codepoints

    def _render(self, concrete_values):
        if self._args.verbose >= 1:
            print(concrete_values)
        (filename_prefix, ascii_der_source) = self._cg.render(concrete_values)

        if self._args.no_pem:
            self._write_raw_ader_file(filename_prefix, ascii_der_source)
        else:
            self._write_pem_file(filename_prefix, ascii_der_source)

    def _write_raw_ader_file(self, filename_prefix, ascii_der_source):
        outfile = self._args.output_dir + "/" + basename + ".ader"
        with open(outfile, "w") as f:
            f.write(ascii_der_source)
        print(ascii_der_source)

    def _write_pem_file(self, filename_prefix, ascii_der_source):
        der_data = subprocess.check_output(["ascii2der"],
                                           input=ascii_der_source.encode())
        try:
            pem_cert = subprocess.check_output(
                ["openssl", "x509", "-inform", "der", "-text"], input=der_data)
            pem_cert = pem_cert.decode()
            pem_cert = [line.rstrip("\t ") for line in pem_cert.split("\n")]
            pem_cert = "\n".join(pem_cert)
        except subprocess.CalledProcessError:
            # OpenSSL cannot encode the certificate
            pem_cert = PEMDataTools.data2pem(der_data, marker="CERTIFICATE")

        codepoints = self._extract_codepoints(filename_prefix, pem_cert)
        if len(codepoints) == 0:
            return

        outfile = self._args.output_dir + "/" + filename_prefix + ".pem"
        with open(outfile, "w") as f:
            f.write(pem_cert)

        tc_filename = "certs/generated/%s/%s.pem" % (self._args.tcname,
                                                     filename_prefix)
        tc = self._TCDefinition(full_name="test_generated_%s_%s" %
                                (self._args.tcname, filename_prefix),
                                filename=tc_filename,
                                expect_present=codepoints)
        self._tcs.append(tc)