示例#1
0
 def decode_qualifier(cls, oid, qualifier_data):
     decoded_qualifier = None
     if oid == OIDDB.X509ExtensionCertificatePolicyQualifierOIDs.inverse(
             "id-qt-cps"):
         decoded_qualifier = ASN1Tools.safe_decode(
             qualifier_data,
             asn1_spec=(rfc5280.CPSuri(), ASN1Models.RelaxedCPSuri()))
     elif oid == OIDDB.X509ExtensionCertificatePolicyQualifierOIDs.inverse(
             "id-qt-unotice"):
         decoded_qualifier = ASN1Tools.safe_decode(
             qualifier_data,
             asn1_spec=(rfc5280.UserNotice(),
                        ASN1Models.RelaxedUserNotice()))
     return decoded_qualifier
示例#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])
示例#3
0
 def test_safedecode_undecodable(self):
     der_data = bytes.fromhex("aa bb cc")
     asn1_details = ASN1Tools.safe_decode(der_data)
     self.assertEqual(asn1_details.flags, set(["undecodable"]))
     self.assertEqual(asn1_details.tail, None)
     self.assertEqual(asn1_details.asn1, None)
     self.assertEqual(asn1_details.generic_asn1, None)
     self.assertEqual(asn1_details.encoded_der, None)
     self.assertEqual(asn1_details.original_der, der_data)
     self.assertEqual(asn1_details.model_index, None)
示例#4
0
 def test_safedecode_ok_nomodel(self):
     der_data = bytes.fromhex("02 01   7b")  # 123
     asn1_details = ASN1Tools.safe_decode(der_data)
     self.assertEqual(asn1_details.flags, set())
     self.assertEqual(asn1_details.tail, bytes())
     self.assertEqual(asn1_details.asn1, Integer(123))
     self.assertEqual(asn1_details.generic_asn1, None)
     self.assertEqual(asn1_details.encoded_der, None)
     self.assertEqual(asn1_details.original_der, der_data)
     self.assertEqual(asn1_details.model_index, 0)
示例#5
0
 def __init__(self, oid, critical, data):
     assert (isinstance(oid, OID))
     assert (isinstance(critical, bool))
     assert (isinstance(data, bytes))
     self._oid = oid
     self._critical = critical
     self._data = data
     self._detailed_asn1 = None
     spec = self._ASN1_MODEL() if (self._ASN1_MODEL is not None) else None
     self._detailed_asn1 = ASN1Tools.safe_decode(self.data, asn1_spec=spec)
     self._decode_hook()
示例#6
0
 def test_safedecode_ok_nonder_trailing_data(self):
     der_data = bytes.fromhex("02 02 007b aabb")  # 123 non-DER
     asn1_details = ASN1Tools.safe_decode(der_data,
                                          asn1_spec=RestrictiveASN1Model())
     self.assertEqual(asn1_details.flags, set(["non_der", "trailing_data"]))
     self.assertEqual(asn1_details.asn1, Integer(123))
     self.assertEqual(asn1_details.tail, bytes.fromhex("aabb"))
     self.assertEqual(asn1_details.generic_asn1, None)
     self.assertEqual(asn1_details.encoded_der, bytes.fromhex("02 01 7b"))
     self.assertEqual(asn1_details.original_der, der_data)
     self.assertEqual(asn1_details.model_index, 0)
示例#7
0
 def test_safedecode_ok_trailing_data(self):
     der_data = bytes.fromhex("02 02 01c8 aabb")  # 456
     asn1_details = ASN1Tools.safe_decode(der_data,
                                          asn1_spec=BasicASN1Model())
     self.assertEqual(asn1_details.flags, set(["trailing_data"]))
     self.assertEqual(asn1_details.asn1, Integer(456))
     self.assertEqual(asn1_details.tail, bytes.fromhex("aa bb"))
     self.assertEqual(asn1_details.generic_asn1, None)
     self.assertEqual(asn1_details.encoded_der, None)
     self.assertEqual(asn1_details.original_der, der_data)
     self.assertEqual(asn1_details.model_index, 0)
示例#8
0
 def test_safedecode_fail_model_generic(self):
     der_data = bytes.fromhex("02 02 01c8")  # 456
     asn1_details = ASN1Tools.safe_decode(der_data,
                                          asn1_spec=RestrictiveASN1Model())
     self.assertEqual(asn1_details.flags, set(["unexpected_type"]))
     self.assertEqual(asn1_details.tail, bytes())
     self.assertEqual(asn1_details.asn1, None)
     self.assertEqual(asn1_details.generic_asn1, Integer(456))
     self.assertEqual(asn1_details.encoded_der, None)
     self.assertEqual(asn1_details.original_der, der_data)
     self.assertEqual(asn1_details.model_index, None)
示例#9
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"]
                                 ]))
示例#10
0
 def test_safedecode_wrong_type(self):
     der_data = bytes.fromhex("04 06 666f6f626172")  # "foobar" OctetString
     asn1_details = ASN1Tools.safe_decode(der_data,
                                          asn1_spec=RestrictiveASN1Model())
     self.assertEqual(asn1_details.flags, set(["unexpected_type"]))
     self.assertEqual(asn1_details.asn1, None)
     self.assertEqual(asn1_details.tail, bytes())
     self.assertEqual(asn1_details.generic_asn1, OctetString(b"foobar"))
     self.assertEqual(asn1_details.encoded_der, None)
     self.assertEqual(asn1_details.original_der, der_data)
     self.assertEqual(asn1_details.model_index, None)
示例#11
0
    def create(cls, parameters):
        asn1 = rfc2459.SubjectPublicKeyInfo()
        asn1["algorithm"] = rfc2459.AlgorithmIdentifier()
        asn1["algorithm"][
            "algorithm"] = OIDDB.KeySpecificationAlgorithms.inverse(
                "id-dsa").to_asn1()
        asn1["algorithm"]["algorithm"] = parameters["curve"].oid.to_asn1()

        inner_key = parameters["curve"].point(parameters["x"],
                                              parameters["y"]).encode()
        asn1["subjectPublicKey"] = ASN1Tools.bytes2bitstring(inner_key)
        return asn1
示例#12
0
 def test_safedecode_non_encodable(self):
     der_data = bytes.fromhex(
         "17 11 31 36 30 32 31 37 31 30 32 37 30 30 2b 30 31 30 30"
     )  # UTCTime("160217102700+0100")
     asn1_details = ASN1Tools.safe_decode(der_data)
     self.assertEqual(asn1_details.flags, set(["non_encodable"]))
     self.assertEqual(asn1_details.asn1, UTCTime("160217102700+0100"))
     self.assertEqual(asn1_details.tail, bytes())
     self.assertEqual(asn1_details.generic_asn1, None)
     self.assertEqual(asn1_details.encoded_der, None)
     self.assertEqual(asn1_details.original_der, der_data)
     self.assertEqual(asn1_details.model_index, 0)
示例#13
0
    def from_subject_pubkey_info(cls, pk_alg, params_asn1, pubkey_data):
        params = ASN1Tools.safe_decode(params_asn1,
                                       asn1_spec=rfc3279.Dss_Parms())
        pubkey = ASN1Tools.safe_decode(pubkey_data,
                                       asn1_spec=rfc3279.DSAPublicKey())

        accessible_parameters = {}
        if params.asn1 is not None:
            accessible_parameters.update({
                "p": int(params.asn1["p"]),
                "q": int(params.asn1["q"]),
                "g": int(params.asn1["g"]),
            })

        if pubkey.asn1 is not None:
            accessible_parameters.update({
                "pubkey": int(pubkey.asn1),
            })

        return cls(accessible_parameters=accessible_parameters,
                   decoding_details=[params, pubkey])
示例#14
0
 def test_safedecode_ok_model_fallback(self):
     der_data = bytes.fromhex("02 02 01c8")  # 456
     asn1_details = ASN1Tools.safe_decode(der_data,
                                          asn1_spec=(RestrictiveASN1Model(),
                                                     BasicASN1Model()))
     self.assertEqual(asn1_details.flags, set(["fallback"]))
     self.assertEqual(asn1_details.tail, bytes())
     self.assertEqual(asn1_details.asn1, Integer(456))
     self.assertEqual(asn1_details.generic_asn1, None)
     self.assertEqual(asn1_details.encoded_der, None)
     self.assertEqual(asn1_details.original_der, der_data)
     self.assertEqual(asn1_details.model_index, 1)
示例#15
0
 def __init__(self, der_data, source=None):
     assert (isinstance(der_data, bytes))
     self._der_data = der_data
     self._asn1_details = ASN1Tools.safe_decode(
         der_data, asn1_spec=self._ASN1_MODEL())
     if self._asn1_details.asn1 is None:
         raise UnexpectedFileContentException(
             "Could not decode ASN.1 blob of length %d as %s." %
             (len(der_data), self.__class__.__name__))
     self._hashval = hashlib.sha256(self._der_data).digest()
     self._source = source
     self._post_decode_hook()
示例#16
0
    def _decode_hook(self):
        if self.asn1 is None:
            self._distribution_points = None
            return

        self._distribution_points = []
        for asn1_point in self.asn1:
            point_name_rdn_malformed = False
            if asn1_point["distributionPoint"].hasValue():
                point_name_asn1 = asn1_point["distributionPoint"].getComponent(
                )
                if asn1_point["distributionPoint"]["fullName"].hasValue():
                    # GeneralNames
                    point_name = ASN1GeneralNamesWrapper.from_asn1(
                        point_name_asn1)
                else:
                    # RelativeDistinguishedName
                    try:
                        point_name = RelativeDistinguishedName.from_asn1(
                            point_name_asn1)
                    except InvalidInputException:
                        point_name = None
                        point_name_rdn_malformed = True
            else:
                point_name = None

            if asn1_point["reasons"].hasValue():
                reasons = set()
                for (bitno, value) in enumerate(asn1_point["reasons"]):
                    if value == 1:
                        value = self._KNOWN_REASON_BITS.get(bitno, bitno)
                        reasons.add(value)
                reasons_trailing_zero = ASN1Tools.bitstring_has_trailing_zeros(
                    asn1_point["reasons"])
            else:
                reasons = None
                reasons_trailing_zero = False

            if asn1_point["cRLIssuer"].hasValue():
                crl_issuer = ASN1GeneralNamesWrapper.from_asn1(
                    asn1_point["cRLIssuer"])
            else:
                crl_issuer = None

            cdp = self._DistributionPoint(
                point_name=point_name,
                point_name_rdn_malformed=point_name_rdn_malformed,
                reasons=reasons,
                reasons_trailing_zero=reasons_trailing_zero,
                crl_issuer=crl_issuer)
            self._distribution_points.append(cdp)
示例#17
0
    def test_bitstring_empty(self):
        self.assertTrue(ASN1Tools.bitstring_is_empty(BitString([])))
        self.assertTrue(ASN1Tools.bitstring_is_empty(BitString([0])))
        self.assertTrue(ASN1Tools.bitstring_is_empty(BitString([0, 0, 0])))

        self.assertFalse(ASN1Tools.bitstring_is_empty(BitString([1])))
        self.assertFalse(ASN1Tools.bitstring_is_empty(BitString([0, 1])))
        self.assertFalse(ASN1Tools.bitstring_is_empty(BitString([0, 0, 1, 0])))
示例#18
0
    def from_subject_pubkey_info(cls, pk_alg, params_asn1, pubkey_data):
        pubkey = ASN1Tools.safe_decode(pubkey_data,
                                       asn1_spec=rfc2437.RSAPublicKey())

        if pubkey.asn1 is not None:
            accessible_parameters = {
                "n": int(pubkey.asn1["modulus"]),
                "e": int(pubkey.asn1["publicExponent"]),
                "params": params_asn1 if params_asn1.hasValue() else None,
            }
        else:
            accessible_parameters = None
        return cls(accessible_parameters=accessible_parameters,
                   decoding_details=pubkey)
示例#19
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"]))
示例#20
0
	def _forge_cert(self, cert_issuer_id, issuer, cert_subject_id, subject):
		self._log.debug("Forging chain element %d -> %d: %s -> %s", cert_issuer_id, cert_subject_id, issuer, subject)
		issuer_key_filename = self._args.key_template % (cert_issuer_id)
		key_filename = self._args.key_template % (cert_subject_id)
		crt_filename = self._args.cert_template % (cert_subject_id)

		if (not os.path.isfile(key_filename)) or self._args.force:
			OpenSSLTools.create_private_key(PrivateKeyStorage(storage_form = PrivateKeyStorageForm.PEM_FILE, filename = key_filename), subject.pubkey.keyspec)

		# Read new private key and convert to public key
		with tempfile.NamedTemporaryFile(prefix = "pubkey_", suffix = ".pem") as pubkey_file:
			OpenSSLTools.private_to_public(key_filename, pubkey_file.name)
			subject_pubkey = PublicKey.read_pemfile(pubkey_file.name)[0]

		# Do the same for the issuer key to get the issuer key ID
		with tempfile.NamedTemporaryFile(prefix = "pubkey_", suffix = ".pem") as pubkey_file:
			OpenSSLTools.private_to_public(issuer_key_filename, pubkey_file.name)
			issuer_pubkey = PublicKey.read_pemfile(pubkey_file.name)[0]

		# Replace public key first
		forged_cert_asn1 = subject.asn1_clone
		forged_cert_asn1["tbsCertificate"]["subjectPublicKeyInfo"] = subject_pubkey.asn1

		# Do identifiers need to be recalculated?
		if self._args.recalculate_keyids:
			if subject.extensions.has(OIDDB.X509Extensions.inverse("SubjectKeyIdentifier")):
				# Replace subject key identifier
				new_key_id = subject_pubkey.keyid()
				replacement_extension = X509SubjectKeyIdentifierExtension.construct(new_key_id)
				subject.extensions.filter(OIDDB.X509Extensions.inverse("SubjectKeyIdentifier"), replacement_extension)

			if subject.extensions.has(OIDDB.X509Extensions.inverse("AuthorityKeyIdentifier")):
				# Replace authority key identifier
				new_key_id = issuer_pubkey.keyid()
				replacement_extension = X509AuthorityKeyIdentifierExtension.construct(new_key_id)
				subject.extensions.filter(OIDDB.X509Extensions.inverse("AuthorityKeyIdentifier"), replacement_extension)

			forged_cert_asn1["tbsCertificate"]["extensions"] = subject.extensions.to_asn1()

		# Re-serialize certificate
		forged_cert = X509Certificate.from_asn1(forged_cert_asn1)

		# Then sign the modified certifiate
		signature = OpenSSLTools.sign_data(subject.signature_algorithm, issuer_key_filename, forged_cert.signed_payload)

		# Finally, place the signature into the certificate
		forged_cert_asn1["signatureValue"] = ASN1Tools.bytes2bitstring(signature)
		forged_cert = X509Certificate.from_asn1(forged_cert_asn1)
		forged_cert.write_pemfile(crt_filename)
示例#21
0
    def create(cls, parameters):
        asn1 = rfc2459.SubjectPublicKeyInfo()
        asn1["algorithm"] = rfc2459.AlgorithmIdentifier()
        asn1["algorithm"][
            "algorithm"] = OIDDB.KeySpecificationAlgorithms.inverse(
                "rsaEncryption").to_asn1()
        asn1["algorithm"]["parameters"] = pyasn1.type.univ.Any(
            value=pyasn1.codec.der.encoder.encode(pyasn1.type.univ.Null()))

        inner_key = rfc2437.RSAPublicKey()
        inner_key["modulus"] = pyasn1.type.univ.Integer(parameters["n"])
        inner_key["publicExponent"] = pyasn1.type.univ.Integer(parameters["e"])
        inner_key = pyasn1.codec.der.encoder.encode(inner_key)
        asn1["subjectPublicKey"] = ASN1Tools.bytes2bitstring(inner_key)
        return asn1
示例#22
0
    def create(cls, parameters):
        asn1 = rfc2459.SubjectPublicKeyInfo()
        asn1["algorithm"] = rfc2459.AlgorithmIdentifier()
        asn1["algorithm"][
            "algorithm"] = OIDDB.KeySpecificationAlgorithms.inverse(
                "id-dsa").to_asn1()
        asn1["algorithm"]["parameters"] = rfc3279.Dss_Parms()
        asn1["algorithm"]["parameters"]["p"] = parameters["p"]
        asn1["algorithm"]["parameters"]["q"] = parameters["q"]
        asn1["algorithm"]["parameters"]["g"] = parameters["g"]

        inner_key = rfc3279.DSAPublicKey(parameters["pubkey"])
        inner_key = pyasn1.codec.der.encoder.encode(inner_key)
        asn1["subjectPublicKey"] = ASN1Tools.bytes2bitstring(inner_key)

        return asn1
示例#23
0
    def test_bitstring_trailing_zero(self):
        self.assertTrue(
            ASN1Tools.bitstring_has_trailing_zeros(BitString([0, 1, 0])))
        self.assertTrue(ASN1Tools.bitstring_has_trailing_zeros(BitString([0])))
        self.assertTrue(
            ASN1Tools.bitstring_has_trailing_zeros(
                BitString([1, 1, 1, 1, 1, 1, 1, 0])))
        self.assertTrue(
            ASN1Tools.bitstring_has_trailing_zeros(
                BitString([1, 1, 1, 1, 1, 1, 1, 1, 0])))

        self.assertFalse(
            ASN1Tools.bitstring_has_trailing_zeros(BitString([0, 1])))
        self.assertFalse(ASN1Tools.bitstring_has_trailing_zeros(BitString([])))
        self.assertFalse(
            ASN1Tools.bitstring_has_trailing_zeros(BitString([0, 0, 0, 0, 1])))
        self.assertFalse(
            ASN1Tools.bitstring_has_trailing_zeros(
                BitString([0, 0, 0, 0, 0, 0, 1])))
        self.assertFalse(
            ASN1Tools.bitstring_has_trailing_zeros(
                BitString([0, 0, 0, 0, 0, 0, 0, 1])))
示例#24
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
示例#25
0
    def create(cls, parameters):
        asn1 = rfc2459.SubjectPublicKeyInfo()

        asn1["algorithm"][
            "algorithm"] = OIDDB.KeySpecificationAlgorithms.inverse(
                "ecPublicKey").to_asn1()
        if parameters["curve"].oid is not None:
            asn1["algorithm"]["parameters"] = pyasn1.codec.der.encoder.encode(
                parameters["curve"].oid.to_asn1())
        else:
            # TODO not implemented
            #domain_params = SpecifiedECDomain()
            #domain_params["version"] = 1
            #asn1["algorithm"]["parameters"] = domain_params
            raise NotImplementedError(
                "Creation of explicitly specified elliptic curve domain parameters (i.e., non-named curves) is not implemented in x509sak"
            )

        inner_key = parameters["curve"].point(parameters["x"],
                                              parameters["y"]).encode()
        asn1["subjectPublicKey"] = ASN1Tools.bytes2bitstring(inner_key)
        return asn1
示例#26
0
    def _analyze_rsa_pss_signature_params(self, signature_alg_params):
        judgements = SecurityJudgements()
        asn1_details = ASN1Tools.safe_decode(
            signature_alg_params, asn1_spec=ASN1Models.RSASSA_PSS_Params())
        judgements += self._DER_VALIDATOR_RSAPSS_PARAMETERS.validate(
            asn1_details)
        if asn1_details.asn1 is not None:
            rsapss = RSAPSSParameters.from_asn1(asn1_details.asn1)
            if rsapss.hash_algorithm is None:
                judgements += SecurityJudgement(
                    JudgementCode.X509Cert_Signature_HashFunction_Unknown,
                    "Certificate has unknown hash function for use in RSA-PSS, OID %s. Cannot make security determination for that part."
                    % (rsapss.hash_algorithm_oid),
                    commonness=Commonness.HIGHLY_UNUSUAL,
                    compatibility=Compatibility.LIMITED_SUPPORT)

            if rsapss.mask_algorithm is None:
                judgements += SecurityJudgement(
                    JudgementCode.
                    X509Cert_PublicKey_RSA_RSA_PSS_UnknownMaskFunction,
                    "Certificate has unknown mask function for use in RSA-PSS, OID %s."
                    % (rsapss.mask_algorithm_oid),
                    commonness=Commonness.HIGHLY_UNUSUAL,
                    compatibility=Compatibility.LIMITED_SUPPORT)

            if rsapss.mask_hash_algorithm is None:
                judgements += SecurityJudgement(
                    JudgementCode.X509Cert_Signature_HashFunction_Unknown,
                    "Certificate has unknown mask hash function for use in RSA-PSS, OID %s."
                    % (rsapss.mask_hash_algorithm_oid),
                    commonness=Commonness.HIGHLY_UNUSUAL,
                    compatibility=Compatibility.LIMITED_SUPPORT)

            if rsapss.trailer_field_value is None:
                judgements += SecurityJudgement(
                    JudgementCode.
                    X509Cert_PublicKey_RSA_RSA_PSS_UnknownTrailerField,
                    "Certificate has unknown trailer field for use in RSA-PSS, trailer field ID %d."
                    % (rsapss.trailer_field),
                    commonness=Commonness.HIGHLY_UNUSUAL,
                    compatibility=Compatibility.LIMITED_SUPPORT)

            if (rsapss.hash_algorithm is not None) and (
                    rsapss.mask_hash_algorithm is not None) and (
                        rsapss.hash_algorithm != rsapss.mask_hash_algorithm):
                standard = RFCReference(
                    rfcno=3447,
                    sect="8.1",
                    verb="RECOMMEND",
                    text=
                    "Therefore, it is recommended that the EMSA-PSS mask generation function be based on the same hash function."
                )
                judgements += SecurityJudgement(
                    JudgementCode.
                    X509Cert_PublicKey_RSA_RSA_PSS_MultipleHashFunctions,
                    "RSA-PSS uses hash function %s for hashing, but %s for masking. This is discouraged."
                    % (rsapss.hash_algorithm.name,
                       rsapss.mask_hash_algorithm.name),
                    commonness=Commonness.HIGHLY_UNUSUAL,
                    compatibility=Compatibility.LIMITED_SUPPORT,
                    standard=standard)

            if rsapss.salt_length < 0:
                judgements += SecurityJudgement(
                    JudgementCode.
                    X509Cert_PublicKey_RSA_RSAPSS_InvalidSaltLength,
                    "Certificate has negative salt length for use in RSA-PSS, %d bytes specified."
                    % (rsapss.salt_length),
                    commonness=Commonness.HIGHLY_UNUSUAL,
                    compatibility=Compatibility.STANDARDS_DEVIATION,
                    bits=0)
            elif rsapss.salt_length == 0:
                judgements += SecurityJudgement(
                    JudgementCode.X509Cert_PublicKey_RSA_RSA_PSS_NoSaltUsed,
                    "RSA-PSS does not use any salt.",
                    commonness=Commonness.HIGHLY_UNUSUAL)
            elif rsapss.salt_length < 16:
                judgements += SecurityJudgement(
                    JudgementCode.X509Cert_PublicKey_RSA_RSA_PSS_ShortSaltUsed,
                    "RSA-PSS uses a comparatively short salt value of %d bits."
                    % (rsapss.salt_length * 8),
                    commonness=Commonness.UNUSUAL)
            else:
                judgements += SecurityJudgement(
                    JudgementCode.
                    X509Cert_PublicKey_RSA_RSA_PSS_SaltLengthInBytes,
                    "RSA-PSS uses a salt of %d bits." %
                    (rsapss.salt_length * 8))
            return (rsapss.hash_algorithm, judgements)
        else:
            return (None, judgements)
示例#27
0
    def analyze(self,
                signature_alg_oid,
                signature_alg_params,
                signature,
                root_cert=None):
        judgements = SecurityJudgements()
        signature_alg = SignatureAlgorithms.lookup("oid", signature_alg_oid)
        if signature_alg is None:
            judgements += SecurityJudgement(
                JudgementCode.X509Cert_Signature_Function_Unknown,
                "Certificate has unknown signature algorithm with OID %s. Cannot make security determination."
                % (signature_alg_oid),
                commonness=Commonness.HIGHLY_UNUSUAL,
                compatibility=Compatibility.LIMITED_SUPPORT)
            result = {
                "name": str(signature_alg_oid),
                "pretty": str(signature_alg_oid),
                "security": judgements,
            }
            return result

        if isinstance(signature_alg.value.oid, (tuple, list)):
            # Have more than one OID for this
            if signature_alg.value.oid[0] != signature_alg_oid:
                judgements += SecurityJudgement(
                    JudgementCode.X509Cert_Signature_Function_DeprecatedOID,
                    "Signature algorithm uses alternate OID %s for algorithm %s. Preferred OID would be %s."
                    % (signature_alg_oid, signature_alg.name,
                       signature_alg.value.oid[0]),
                    commonness=Commonness.HIGHLY_UNUSUAL,
                    compatibility=Compatibility.LIMITED_SUPPORT)

        if signature_alg.value.hash_fnc is not None:
            # Signature algorithm already implies a concrete hash function, already done.
            hash_fnc = signature_alg.value.hash_fnc
        else:
            # Signature algorithms depends and is not implied.
            (hash_fnc, new_judgements) = self._determine_hash_function(
                signature_alg, signature_alg_params)
            judgements += new_judgements

        if signature_alg.value.sig_fnc == SignatureFunctions.ecdsa:
            # Decode ECDSA signature
            asn1_details = ASN1Tools.safe_decode(
                signature, asn1_spec=rfc3279.ECDSA_Sig_Value())
            judgements += self._DER_VALIDATOR_ECDSA_SIGNATURE.validate(
                asn1_details)
            if (asn1_details.asn1 is not None) and (root_cert is not None):
                if root_cert.pubkey.pk_alg.value.cryptosystem == Cryptosystems.ECC_ECDSA:
                    # Check that this is really a potential parent CA certificate
                    ca_curve = root_cert.pubkey.curve
                    hweight_analysis = NumberTheory.hamming_weight_analysis(
                        int(asn1_details.asn1["r"]),
                        min_bit_length=ca_curve.field_bits)
                    if not hweight_analysis.plausibly_random:
                        judgements += SecurityJudgement(
                            JudgementCode.
                            X509Cert_Signature_ECDSA_R_BitBiasPresent,
                            "Hamming weight of ECDSA signature R parameter is %d at bitlength %d, but expected a weight between %d and %d when randomly chosen; this is likely not coincidential."
                            %
                            (hweight_analysis.hweight, hweight_analysis.bitlen,
                             hweight_analysis.rnd_min_hweight,
                             hweight_analysis.rnd_max_hweight),
                            commonness=Commonness.HIGHLY_UNUSUAL)
                    hweight_analysis = NumberTheory.hamming_weight_analysis(
                        int(asn1_details.asn1["s"]),
                        min_bit_length=ca_curve.field_bits)
                    if not hweight_analysis.plausibly_random:
                        judgements += SecurityJudgement(
                            JudgementCode.
                            X509Cert_Signature_ECDSA_S_BitBiasPresent,
                            "Hamming weight of ECDSA signature S parameter is %d at bitlength %d, but expected a weight between %d and %d when randomly chosen; this is likely not coincidential."
                            %
                            (hweight_analysis.hweight, hweight_analysis.bitlen,
                             hweight_analysis.rnd_min_hweight,
                             hweight_analysis.rnd_max_hweight),
                            commonness=Commonness.HIGHLY_UNUSUAL)

        elif signature_alg.value.sig_fnc == SignatureFunctions.dsa:
            # Decode DSA signature
            asn1_details = ASN1Tools.safe_decode(
                signature, asn1_spec=rfc3279.Dss_Sig_Value())
            judgements += self._DER_VALIDATOR_DSA_SIGNATURE.validate(
                asn1_details)
            if (asn1_details.asn1 is not None) and (root_cert is not None):
                if root_cert is not None:
                    if root_cert.pubkey.pk_alg.value.cryptosystem == Cryptosystems.DSA:
                        field_width = root_cert.pubkey.q.bit_length()

                        hweight_analysis = NumberTheory.hamming_weight_analysis(
                            int(asn1_details.asn1["r"]),
                            min_bit_length=field_width)
                        if not hweight_analysis.plausibly_random:
                            judgements += SecurityJudgement(
                                JudgementCode.
                                X509Cert_Signature_DSA_R_BitBiasPresent,
                                "Hamming weight of DSA signature R parameter is %d at bitlength %d, but expected a weight between %d and %d when randomly chosen; this is likely not coincidential."
                                % (hweight_analysis.hweight,
                                   hweight_analysis.bitlen,
                                   hweight_analysis.rnd_min_hweight,
                                   hweight_analysis.rnd_max_hweight),
                                commonness=Commonness.HIGHLY_UNUSUAL)

                        hweight_analysis = NumberTheory.hamming_weight_analysis(
                            int(asn1_details.asn1["s"]),
                            min_bit_length=field_width)
                        if not hweight_analysis.plausibly_random:
                            judgements += SecurityJudgement(
                                JudgementCode.
                                X509Cert_Signature_DSA_S_BitBiasPresent,
                                "Hamming weight of DSA signature S parameter is %d at bitlength %d, but expected a weight between %d and %d when randomly chosen; this is likely not coincidential."
                                % (hweight_analysis.hweight,
                                   hweight_analysis.bitlen,
                                   hweight_analysis.rnd_min_hweight,
                                   hweight_analysis.rnd_max_hweight),
                                commonness=Commonness.HIGHLY_UNUSUAL)

        result = {
            "name":
            signature_alg.name,
            "sig_fnc":
            self.algorithm("sig_fnc").analyze(signature_alg.value.sig_fnc),
            "security":
            judgements,
        }
        if hash_fnc is not None:
            result.update({
                "pretty":
                signature_alg.value.sig_fnc.value.pretty_name + " with " +
                hash_fnc.value.pretty_name,
                "hash_fnc":
                self.algorithm("hash_fnc").analyze(hash_fnc),
            })
        else:
            result.update({
                "pretty":
                "%s with undetermined hash function" %
                (signature_alg.value.sig_fnc.value.pretty_name)
            })
        return result
示例#28
0
 def valid_not_before(self):
     return ASN1Tools.parse_datetime(
         str(self.asn1["tbsCertificate"]["validity"]
             ["notBefore"].getComponent()))
示例#29
0
 def signature(self):
     signature = ASN1Tools.bitstring2bytes(self.asn1["signatureValue"])
     return signature
示例#30
0
 def keyid(self, hashfnc="sha1"):
     hashval = hashlib.new(hashfnc)
     inner_key = ASN1Tools.bitstring2bytes(self.asn1["subjectPublicKey"])
     hashval.update(inner_key)
     return hashval.digest()