Example #1
0
    def testDerCodec(self):
        substrate = pem.readBase64fromText(self.pem_text)
        asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec)
        assert not rest
        assert asn1Object.prettyPrint()
        assert der_encode(asn1Object) == substrate

        assert asn1Object['acinfo']['version'] == 1

        attributeMap = {
            rfc3281.id_at_role: rfc3281.RoleSyntax(),
            rfc3281.id_aca_authenticationInfo: rfc3281.SvceAuthInfo(),
            rfc3281.id_aca_accessIdentity: rfc3281.SvceAuthInfo(),
            rfc3281.id_aca_chargingIdentity: rfc3281.IetfAttrSyntax(),
            rfc3281.id_aca_group: rfc3281.IetfAttrSyntax(),
        }

        count = 0
        for attr in asn1Object['acinfo']['attributes']:
            assert attr['type'] in attributeMap
            av, rest = der_decode(attr['values'][0],
                                  asn1Spec=attributeMap[attr['type']])
            assert not rest
            assert av.prettyPrint()
            assert der_encode(av) == attr['values'][0]
            count += 1

        assert count == 5
    def testDerCodec(self):
        substrate = pem.readBase64fromText(self.pem_text)
        asn1Object, rest = der_decoder(substrate, asn1Spec=self.asn1Spec)

        self.assertFalse(rest)
        self.assertTrue(asn1Object.prettyPrint())
        self.assertEqual(substrate, der_encoder(asn1Object))
        self.assertEqual(1, asn1Object['acinfo']['version'])

        attributeMap = {
            rfc3281.id_at_role: rfc3281.RoleSyntax(),
            rfc3281.id_aca_authenticationInfo: rfc3281.SvceAuthInfo(),
            rfc3281.id_aca_accessIdentity: rfc3281.SvceAuthInfo(),
            rfc3281.id_aca_chargingIdentity: rfc3281.IetfAttrSyntax(),
            rfc3281.id_aca_group: rfc3281.IetfAttrSyntax(),
        }

        count = 0

        for attr in asn1Object['acinfo']['attributes']:
            self.assertIn(attr['type'], attributeMap)

            av, rest = der_decoder(attr['values'][0],
                                   asn1Spec=attributeMap[attr['type']])

            self.assertFalse(rest)
            self.assertTrue(av.prettyPrint())
            self.assertEqual(attr['values'][0], der_encoder(av))

            count += 1

        self.assertEqual(5, count)
Example #3
0
def decodeVOMSExtension(m2cert):
    """Decode the content of the VOMS extension

    :param m2cert: M2Crypto X509 object, a certificate

    :returns: A dictionnary containing the following fields:

      * notBefore: datetime.datetime
      * notAfter: datetime.datetime
      * attribute: (string). Comma separated list of VOMS tags presented as bellow

                             "<tagName> = <tagValue> (<tagQualifier>)"
                             Typically, the nickname will look like
                             'nickname = chaen (lhcb)',

      * fqan: List of VOMS "position" (['/lhcb/Role=production/Capability=NULL', '/lhcb/Role=NULL/Capability=NULL'])
      * vo: name of the VO,
      * subject: subject DN to which the attributes were granted,
      * issuer: typically the DN of the VOMS server (e.g '/DC=ch/DC=cern/OU=computers/CN=lcg-voms2.cern.ch')

    """
    vomsExtensionDict = {}
    vomsExtensionOctetString = retrieveExtension(m2cert, VOMS_EXTENSION_OID)
    # Decode it as a ACSequenceOfSequence, which is what it is...
    vomsExtensionSeqOfSeq, _rest = der_decode(vomsExtensionOctetString,
                                              asn1Spec=_ACSequenceOfSequence())

    # In principle, according to GFD 182, there could be more than one VO VOMS AC per proxy.
    # The standard specifies that we have to accept at least the first one, which is what
    # I will do...
    vomsCertAttribute = vomsExtensionSeqOfSeq[0][0]

    ######
    # TODO in principle, we should check the signature of the Attribute...
    # _signatureAlgorith = vomsCertAttribute['signatureAlgorithm']
    # _signatureValue = vomsCertAttribute['signatureValue']
    ######

    certAttrInfo = vomsCertAttribute["acinfo"]

    # pyasn1 does things correctly by setting a timezone info in the datetime
    # However, we do not in DIRAC, and so we can't compare the dates.
    # We have to remove the timezone info from the datetime objects

    notBefore = certAttrInfo["attrCertValidityPeriod"][
        "notBeforeTime"].asDateTime
    vomsExtensionDict["notBefore"] = notBefore.replace(tzinfo=None)

    notAfter = certAttrInfo["attrCertValidityPeriod"][
        "notAfterTime"].asDateTime
    vomsExtensionDict["notAfter"] = notAfter.replace(tzinfo=None)

    # ######### Retrieving the issuer ##########
    # Get the issuer. A bit tricky, because we have to reconstruct the full DN ourselves
    # The GFD 182 and RFC 3281 give enough restriction such that we can afford some direct
    # [0] access

    issuer = ""

    # rdnName is a rfc3280.RelativeDistinguishedName object
    for rdnName in certAttrInfo["issuer"]["v2Form"]["issuerName"][0][
            "directoryName"]["rdnSequence"]:
        # rdnNameAttr rfc3280.AttributeTypeAndValue'
        rdnNameAttr = rdnName[0]

        attrOid = ".".join([str(e) for e in rdnNameAttr["type"].asTuple()])

        # Now finally convert the last part into a asn1char.*String
        attrValStr = _decodeASN1String(rdnNameAttr["value"])
        attrVal = attrValStr.asOctets().decode()
        #
        issuer += "%s%s" % (DN_MAPPING[attrOid], attrVal)

    vomsExtensionDict["issuer"] = issuer

    # ### Issuer retrieved #####

    # ## Retrieving the Subject ####
    # We have to do the same for the subject than for the issuer

    subject = ""

    # rdnName is a rfc3280.RelativeDistinguishedName object
    for rdnName in certAttrInfo["holder"]["baseCertificateID"]["issuer"][0][
            "directoryName"]["rdnSequence"]:
        # rdnNameAttr rfc3280.AttributeTypeAndValue'
        rdnNameAttr = rdnName[0]

        attrOid = ".".join([str(e) for e in rdnNameAttr["type"].asTuple()])
        # # Because there are non printable characters in the values (new line, etc)
        # # we have to get ride of them. The best way is to get them as number, and make sure it is a
        # # a printable char (between 32 and 126)
        #
        # attrVal = ''.join([chr(c) for c in rdnNameAttr['value'].asNumbers() if 32 <= c <= 126 ])

        # Now finally convert the last part into a asn1char.*String
        attrValStr = _decodeASN1String(rdnNameAttr["value"])
        attrVal = attrValStr.asOctets().decode()

        subject += "%s%s" % (DN_MAPPING[attrOid], attrVal)

    vomsExtensionDict["subject"] = subject

    # ### Retrieving the FQAN ####

    # According to GFD182, there may be more attributes that just the FQAN, even though it
    # does not seem to be the case in practice. So we make sure to have the good one
    fqanOIDObj = univ.ObjectIdentifier(VOMS_FQANS_OID)

    # There shall be only one, hense the [0]
    # This is an rfc3280.Attribute object
    fqanAttrObj = [
        attrObj for attrObj in certAttrInfo["attributes"]
        if attrObj["type"] == fqanOIDObj
    ][0]

    # According to GFD182 3.4.1, we decode the value as a IetfAttrSyntax.
    # Since multiple values are not allowed, just take the first item
    #
    fqanObj, _rest = der_decode(fqanAttrObj["values"][0],
                                asn1Spec=rfc3281.IetfAttrSyntax())

    # We retrieve the VO and the VOMS server
    voName, _, _ = fqanObj["policyAuthority"][0][
        "uniformResourceIdentifier"].asOctets().decode().split(":")

    vomsExtensionDict["vo"] = voName

    # Now retrieve the position of the holder (group, role)
    fqanList = []
    for fqanPositionObj in fqanObj["values"]:
        fqanList.append(fqanPositionObj["octets"].asOctets().decode())

    vomsExtensionDict["fqan"] = fqanList

    # ############ End of the FQAN ################

    # Now the Tags, called attributes in the dict...

    tagDescriptions = []
    vomsTagsOIDObj = univ.ObjectIdentifier(VOMS_TAGS_EXT_OID)

    # First find the tag containers
    tagExtensionObj = [
        extObj for extObj in certAttrInfo["extensions"]
        if extObj["extnID"] == vomsTagsOIDObj
    ]

    # If we found tags
    if tagExtensionObj:
        # Multiple is forbiden, so only one tag container
        tagExtensionObj = tagExtensionObj[0]

        tagContainersObj, _rest = der_decode(tagExtensionObj["extnValue"],
                                             asn1Spec=_TagContainers())

        # TODO in principle, we should check that this value
        # and the one of the policyAuthority of the fqan are the same
        # _tagPolicyAuthority = tagContainersObj[0][0]['policyAuthority'][0]['uniformResourceIdentifier'] \
        #     .asOctets().decode()
        ######

        for tagContainer in tagContainersObj:
            for tagList in tagContainer:
                # Note: it is here that I should check the policyAuthority
                tagList = tagList["tags"]
                for tag in tagList:
                    # This gives a string like
                    # nickname = chaen (lhcb)
                    tagDescriptions.append("%s = %s (%s)" % (
                        tag["name"].asOctets().decode(),
                        tag["value"].asOctets().decode(),
                        tag["qualifier"].asOctets().decode(),
                    ))

        vomsExtensionDict["attribute"] = ",".join(tagDescriptions)

    # #### Tags are done ################

    return vomsExtensionDict