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"])))
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])
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)
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
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)
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"])))
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)
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"] ]))
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)
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"]))
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
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:]
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
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 registered_id(self): assert (self.name == "registeredID") if self._cached is None: self._cached = OID.from_asn1(self.asn1_value) return self._cached