diff options
-rw-r--r-- | CHANGES.txt | 5 | ||||
-rw-r--r-- | pyasn1_modules/rfc3114.py | 77 | ||||
-rw-r--r-- | pyasn1_modules/rfc5755.py | 398 | ||||
-rw-r--r-- | pyasn1_modules/rfc5913.py | 44 | ||||
-rw-r--r-- | pyasn1_modules/rfc5917.py | 55 | ||||
-rw-r--r-- | tests/__main__.py | 4 | ||||
-rw-r--r-- | tests/test_rfc3114.py | 235 | ||||
-rw-r--r-- | tests/test_rfc5755.py | 190 | ||||
-rw-r--r-- | tests/test_rfc5913.py | 114 | ||||
-rw-r--r-- | tests/test_rfc5917.py | 112 |
10 files changed, 1234 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 3edd67b..49172ae 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -28,6 +28,11 @@ Revision 0.2.8, released XX-XX-2019 - Update RFC8226 to use ComponentPresentConstraint() instead of the previous work around - Add RFC2631 providing OtherInfo for Diffie-Hellman Key Agreement +- Add RFC3114 providing test values for the S/MIME Security Label +- Add RFC5755 providing Attribute Certificate Profile for Authorization +- Add RFC5913 providing Clearance Attribute and Authority Clearance + Constraints Certificate Extension +- Add RFC5917 providing Clearance Sponsor Attribute Revision 0.2.7, released 09-10-2019 ----------------------------------- diff --git a/pyasn1_modules/rfc3114.py b/pyasn1_modules/rfc3114.py new file mode 100644 index 0000000..badcb1f --- /dev/null +++ b/pyasn1_modules/rfc3114.py @@ -0,0 +1,77 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley with assistance from asn1ate v.0.6.0. +# +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# +# TEST Company Classification Policies +# +# ASN.1 source from: +# https://www.rfc-editor.org/rfc/rfc3114.txt +# + +from pyasn1.type import char +from pyasn1.type import namedval +from pyasn1.type import univ + +from pyasn1_modules import rfc5755 + + +id_smime = univ.ObjectIdentifier((1, 2, 840, 113549, 1, 9, 16, )) + +id_tsp = id_smime + (7, ) + +id_tsp_TEST_Amoco = id_tsp + (1, ) + +class Amoco_SecurityClassification(univ.Integer): + namedValues = namedval.NamedValues( + ('amoco-general', 6), + ('amoco-confidential', 7), + ('amoco-highly-confidential', 8) + ) + + +id_tsp_TEST_Caterpillar = id_tsp + (2, ) + +class Caterpillar_SecurityClassification(univ.Integer): + namedValues = namedval.NamedValues( + ('caterpillar-public', 6), + ('caterpillar-green', 7), + ('caterpillar-yellow', 8), + ('caterpillar-red', 9) + ) + + +id_tsp_TEST_Whirlpool = id_tsp + (3, ) + +class Whirlpool_SecurityClassification(univ.Integer): + namedValues = namedval.NamedValues( + ('whirlpool-public', 6), + ('whirlpool-internal', 7), + ('whirlpool-confidential', 8) + ) + + +id_tsp_TEST_Whirlpool_Categories = id_tsp + (4, ) + +class SecurityCategoryValues(univ.SequenceOf): + componentType = char.UTF8String() + +# Example SecurityCategoryValues: "LAW DEPARTMENT USE ONLY" +# Example SecurityCategoryValues: "HUMAN RESOURCES USE ONLY" + + +# Also, the privacy mark in the security label can contain a string, +# such as: "ATTORNEY-CLIENT PRIVILEGED INFORMATION" + + +# Map of security category type OIDs to security category added +# to the ones that are in rfc5755.py + +_securityCategoryMapUpdate = { + id_tsp_TEST_Whirlpool_Categories: SecurityCategoryValues(), +} + +rfc5755.securityCategoryMap.update(_securityCategoryMapUpdate) diff --git a/pyasn1_modules/rfc5755.py b/pyasn1_modules/rfc5755.py new file mode 100644 index 0000000..14f56fc --- /dev/null +++ b/pyasn1_modules/rfc5755.py @@ -0,0 +1,398 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley with assistance from asn1ate v.0.6.0. +# +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# +# An Internet Attribute Certificate Profile for Authorization +# +# ASN.1 source from: +# https://www.rfc-editor.org/rfc/rfc5755.txt +# https://www.rfc-editor.org/rfc/rfc5912.txt (see Section 13) +# + +from pyasn1.type import char +from pyasn1.type import constraint +from pyasn1.type import namedtype +from pyasn1.type import namedval +from pyasn1.type import opentype +from pyasn1.type import tag +from pyasn1.type import univ +from pyasn1.type import useful + +from pyasn1_modules import rfc5280 +from pyasn1_modules import rfc5652 + +MAX = float('inf') + +# Map for Security Category type to value + +securityCategoryMap = { } + + +# Imports from RFC 5652 + +ContentInfo = rfc5652.ContentInfo + + +# Imports from RFC 5280 + +AlgorithmIdentifier = rfc5280.AlgorithmIdentifier + +Attribute = rfc5280.Attribute + +AuthorityInfoAccessSyntax = rfc5280.AuthorityInfoAccessSyntax + +AuthorityKeyIdentifier = rfc5280.AuthorityKeyIdentifier + +CertificateSerialNumber = rfc5280.CertificateSerialNumber + +CRLDistributionPoints = rfc5280.CRLDistributionPoints + +Extensions = rfc5280.Extensions + +Extension = rfc5280.Extension + +GeneralNames = rfc5280.GeneralNames + +GeneralName = rfc5280.GeneralName + +UniqueIdentifier = rfc5280.UniqueIdentifier + + +# Object Identifier arcs + +id_pkix = univ.ObjectIdentifier((1, 3, 6, 1, 5, 5, 7, )) + +id_pe = id_pkix + (1, ) + +id_kp = id_pkix + (3, ) + +id_aca = id_pkix + (10, ) + +id_ad = id_pkix + (48, ) + +id_at = univ.ObjectIdentifier((2, 5, 4, )) + +id_ce = univ.ObjectIdentifier((2, 5, 29, )) + + +# Attribute Certificate + +class AttCertVersion(univ.Integer): + namedValues = namedval.NamedValues( + ('v2', 1) + ) + + +class IssuerSerial(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('issuer', GeneralNames()), + namedtype.NamedType('serial', CertificateSerialNumber()), + namedtype.OptionalNamedType('issuerUID', UniqueIdentifier()) + ) + + +class ObjectDigestInfo(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('digestedObjectType', + univ.Enumerated(namedValues=namedval.NamedValues( + ('publicKey', 0), + ('publicKeyCert', 1), + ('otherObjectTypes', 2)))), + namedtype.OptionalNamedType('otherObjectTypeID', + univ.ObjectIdentifier()), + namedtype.NamedType('digestAlgorithm', + AlgorithmIdentifier()), + namedtype.NamedType('objectDigest', + univ.BitString()) + ) + + +class Holder(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.OptionalNamedType('baseCertificateID', + IssuerSerial().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatConstructed, 0))), + namedtype.OptionalNamedType('entityName', + GeneralNames().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 1))), + namedtype.OptionalNamedType('objectDigestInfo', + ObjectDigestInfo().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatConstructed, 2))) +) + + +class V2Form(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.OptionalNamedType('issuerName', + GeneralNames()), + namedtype.OptionalNamedType('baseCertificateID', + IssuerSerial().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatConstructed, 0))), + namedtype.OptionalNamedType('objectDigestInfo', + ObjectDigestInfo().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatConstructed, 1))) + ) + + +class AttCertIssuer(univ.Choice): + componentType = namedtype.NamedTypes( + namedtype.NamedType('v1Form', GeneralNames()), + namedtype.NamedType('v2Form', V2Form().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatConstructed, 0))) + ) + + +class AttCertValidityPeriod(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('notBeforeTime', useful.GeneralizedTime()), + namedtype.NamedType('notAfterTime', useful.GeneralizedTime()) + ) + + +class AttributeCertificateInfo(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('version', + AttCertVersion()), + namedtype.NamedType('holder', + Holder()), + namedtype.NamedType('issuer', + AttCertIssuer()), + namedtype.NamedType('signature', + AlgorithmIdentifier()), + namedtype.NamedType('serialNumber', + CertificateSerialNumber()), + namedtype.NamedType('attrCertValidityPeriod', + AttCertValidityPeriod()), + namedtype.NamedType('attributes', + univ.SequenceOf(componentType=Attribute())), + namedtype.OptionalNamedType('issuerUniqueID', + UniqueIdentifier()), + namedtype.OptionalNamedType('extensions', + Extensions()) + ) + + +class AttributeCertificate(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('acinfo', AttributeCertificateInfo()), + namedtype.NamedType('signatureAlgorithm', AlgorithmIdentifier()), + namedtype.NamedType('signatureValue', univ.BitString()) + ) + + +# Attribute Certificate Extensions + +id_pe_ac_auditIdentity = id_pe + (4, ) + +id_ce_noRevAvail = id_ce + (56, ) + +id_ce_targetInformation = id_ce + (55, ) + + +class TargetCert(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('targetCertificate', IssuerSerial()), + namedtype.OptionalNamedType('targetName', GeneralName()), + namedtype.OptionalNamedType('certDigestInfo', ObjectDigestInfo()) + ) + + +class Target(univ.Choice): + componentType = namedtype.NamedTypes( + namedtype.NamedType('targetName', + GeneralName().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 0))), + namedtype.NamedType('targetGroup', + GeneralName().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 1))), + namedtype.NamedType('targetCert', + TargetCert().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatConstructed, 2))) + ) + + +class Targets(univ.SequenceOf): + componentType = Target() + + +id_pe_ac_proxying = id_pe + (10, ) + + +class ProxyInfo(univ.SequenceOf): + componentType = Targets() + + +id_pe_aaControls = id_pe + (6, ) + + +class AttrSpec(univ.SequenceOf): + componentType = univ.ObjectIdentifier() + + +class AAControls(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.OptionalNamedType('pathLenConstraint', + univ.Integer().subtype( + subtypeSpec=constraint.ValueRangeConstraint(0, MAX))), + namedtype.OptionalNamedType('permittedAttrs', + AttrSpec().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 0))), + namedtype.OptionalNamedType('excludedAttrs', + AttrSpec().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 1))), + namedtype.DefaultedNamedType('permitUnSpecified', + univ.Boolean().subtype(value=1)) + ) + + +# Attribute Certificate Attributes + +id_aca_authenticationInfo = id_aca + (1, ) + + +id_aca_accessIdentity = id_aca + (2, ) + + +class SvceAuthInfo(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('service', GeneralName()), + namedtype.NamedType('ident', GeneralName()), + namedtype.OptionalNamedType('authInfo', univ.OctetString()) + ) + + +id_aca_chargingIdentity = id_aca + (3, ) + + +id_aca_group = id_aca + (4, ) + + +class IetfAttrSyntax(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.OptionalNamedType('policyAuthority', + GeneralNames().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 0))), + namedtype.NamedType('values', univ.SequenceOf( + componentType=univ.Choice(componentType=namedtype.NamedTypes( + namedtype.NamedType('octets', univ.OctetString()), + namedtype.NamedType('oid', univ.ObjectIdentifier()), + namedtype.NamedType('string', char.UTF8String()) + )) + )) + ) + + +id_at_role = id_at + (72,) + + +class RoleSyntax(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.OptionalNamedType('roleAuthority', + GeneralNames().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 0))), + namedtype.NamedType('roleName', + GeneralName().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 1))) + ) + + +class ClassList(univ.BitString): + namedValues = namedval.NamedValues( + ('unmarked', 0), + ('unclassified', 1), + ('restricted', 2), + ('confidential', 3), + ('secret', 4), + ('topSecret', 5) + ) + + +class SecurityCategory(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('type', + univ.ObjectIdentifier().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 0))), + namedtype.NamedType('value', + univ.Any().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 1)), + openType=opentype.OpenType('type', securityCategoryMap)) + ) + + +id_at_clearance = univ.ObjectIdentifier((2, 5, 4, 55, )) + + +class Clearance(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('policyId', + univ.ObjectIdentifier()), + namedtype.DefaultedNamedType('classList', + ClassList().subtype(value='unclassified')), + namedtype.OptionalNamedType('securityCategories', + univ.SetOf(componentType=SecurityCategory())) + ) + + +id_at_clearance_rfc3281 = univ.ObjectIdentifier((2, 5, 1, 5, 55, )) + + +class Clearance_rfc3281(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('policyId', + univ.ObjectIdentifier().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 0))), + namedtype.DefaultedNamedType('classList', + ClassList().subtype(implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 1)).subtype( + value='unclassified')), + namedtype.OptionalNamedType('securityCategories', + univ.SetOf(componentType=SecurityCategory()).subtype( + implicitTag=tag.Tag( + tag.tagClassContext, tag.tagFormatSimple, 2))) + ) + + +id_aca_encAttrs = id_aca + (6, ) + + +class ACClearAttrs(univ.Sequence): + componentType = namedtype.NamedTypes( + namedtype.NamedType('acIssuer', GeneralName()), + namedtype.NamedType('acSerial', univ.Integer()), + namedtype.NamedType('attrs', univ.SequenceOf(componentType=Attribute())) + ) + + +# Map of Certificate Extension OIDs to Extensions added to the +# ones that are in rfc5280.py + +_certificateExtensionsMapUpdate = { + id_pe_ac_auditIdentity: univ.OctetString(), + id_ce_noRevAvail: univ.Null(), + id_ce_targetInformation: Targets(), + id_pe_ac_proxying: ProxyInfo(), + id_pe_aaControls: AAControls(), +} + +rfc5280.certificateExtensionsMap.update(_certificateExtensionsMapUpdate) + + +# Map of AttributeType OIDs to AttributeValue added to the +# ones that are in rfc5280.py + +_certificateAttributesMapUpdate = { + id_aca_authenticationInfo: SvceAuthInfo(), + id_aca_accessIdentity: SvceAuthInfo(), + id_aca_chargingIdentity: IetfAttrSyntax(), + id_aca_group: IetfAttrSyntax(), + id_at_role: RoleSyntax(), + id_at_clearance: Clearance(), + id_at_clearance_rfc3281: Clearance_rfc3281(), + id_aca_encAttrs: ContentInfo(), +} + +rfc5280.certificateAttributesMap.update(_certificateAttributesMapUpdate) diff --git a/pyasn1_modules/rfc5913.py b/pyasn1_modules/rfc5913.py new file mode 100644 index 0000000..0bd0653 --- /dev/null +++ b/pyasn1_modules/rfc5913.py @@ -0,0 +1,44 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley with assistance from asn1ate v.0.6.0. +# +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# +# Authority Clearance Constraints Certificate Extension +# +# ASN.1 source from: +# https://www.rfc-editor.org/rfc/rfc5913.txt +# https://www.rfc-editor.org/errata/eid5890 +# + +from pyasn1.type import constraint +from pyasn1.type import univ + +from pyasn1_modules import rfc5280 +from pyasn1_modules import rfc5755 + +MAX = float('inf') + + +# Authority Clearance Constraints Certificate Extension + +id_pe_clearanceConstraints = univ.ObjectIdentifier('1.3.6.1.5.5.7.1.21') + +id_pe_authorityClearanceConstraints = id_pe_clearanceConstraints + + +class AuthorityClearanceConstraints(univ.SequenceOf): + componentType = rfc5755.Clearance() + subtypeSpec=constraint.ValueSizeConstraint(1, MAX) + + +# Map of Certificate Extension OIDs to Extensions added to the +# ones that are in rfc5280.py + +_certificateExtensionsMapUpdate = { + id_pe_clearanceConstraints: AuthorityClearanceConstraints(), +} + +rfc5280.certificateExtensionsMap.update(_certificateExtensionsMapUpdate) diff --git a/pyasn1_modules/rfc5917.py b/pyasn1_modules/rfc5917.py new file mode 100644 index 0000000..ed9af98 --- /dev/null +++ b/pyasn1_modules/rfc5917.py @@ -0,0 +1,55 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley. +# +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# +# Clearance Sponsor Attribute +# +# ASN.1 source from: +# https://www.rfc-editor.org/rfc/rfc5917.txt +# https://www.rfc-editor.org/errata/eid4558 +# https://www.rfc-editor.org/errata/eid5883 +# + +from pyasn1.type import char +from pyasn1.type import constraint +from pyasn1.type import namedtype +from pyasn1.type import univ + +from pyasn1_modules import rfc5280 + + +# DirectoryString is the same as RFC 5280, except for two things: +# 1. the length is limited to 64; +# 2. only the 'utf8String' choice remains because the ASN.1 +# specification says: ( WITH COMPONENTS { utf8String PRESENT } ) + +class DirectoryString(univ.Choice): + componentType = namedtype.NamedTypes( + namedtype.NamedType('utf8String', char.UTF8String().subtype( + subtypeSpec=constraint.ValueSizeConstraint(1, 64))), + ) + + +# Clearance Sponsor Attribute + +id_clearanceSponsor = univ.ObjectIdentifier((2, 16, 840, 1, 101, 2, 1, 5, 68)) + +ub_clearance_sponsor = univ.Integer(64) + + +at_clearanceSponsor = rfc5280.Attribute() +at_clearanceSponsor['type'] = id_clearanceSponsor +at_clearanceSponsor['values'][0] = DirectoryString() + + +# Add to the map of Attribute Type OIDs to Attributes in rfc5280.py. + +_certificateAttributesMapUpdate = { + id_clearanceSponsor: DirectoryString(), +} + +rfc5280.certificateAttributesMap.update(_certificateAttributesMapUpdate) diff --git a/tests/__main__.py b/tests/__main__.py index c1fa4f7..479cd09 100644 --- a/tests/__main__.py +++ b/tests/__main__.py @@ -22,6 +22,7 @@ suite = unittest.TestLoader().loadTestsFromNames( 'tests.test_rfc2634.suite', 'tests.test_rfc2985.suite', 'tests.test_rfc2986.suite', + 'tests.test_rfc3114.suite', 'tests.test_rfc3161.suite', 'tests.test_rfc3274.suite', 'tests.test_rfc3279.suite', @@ -49,9 +50,12 @@ suite = unittest.TestLoader().loadTestsFromNames( 'tests.test_rfc5649.suite', 'tests.test_rfc5652.suite', 'tests.test_rfc5751.suite', + 'tests.test_rfc5755.suite', + 'tests.test_rfc5913.suite', 'tests.test_rfc5914.suite', 'tests.test_rfc5915.suite', 'tests.test_rfc5916.suite', + 'tests.test_rfc5917.suite', 'tests.test_rfc5924.suite', 'tests.test_rfc5934.suite', 'tests.test_rfc5940.suite', diff --git a/tests/test_rfc3114.py b/tests/test_rfc3114.py new file mode 100644 index 0000000..537fe9a --- /dev/null +++ b/tests/test_rfc3114.py @@ -0,0 +1,235 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# + +import sys + +from pyasn1.codec.der.decoder import decode as der_decode +from pyasn1.codec.der.encoder import encode as der_encode + +from pyasn1_modules import pem +from pyasn1_modules import rfc3114 +from pyasn1_modules import rfc5035 +from pyasn1_modules import rfc5083 +from pyasn1_modules import rfc5084 +from pyasn1_modules import rfc5280 +from pyasn1_modules import rfc5652 +from pyasn1_modules import rfc5755 + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class SecurityLabelTestCase(unittest.TestCase): + pem_text = """\ +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 +bXBsZS5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ9/m9uACpsTl2frBuILHiw +IJyfUEpKseYJ+JYL1AtIZU0YeJ9DA+32h0ZeNGJDtDClnbBEPpn3W/5+TzldcsTe +QlAJB08gcVRjkQym9LtPq7rGubCeVWlRRE9M7F9znk6jggGtMIIBqTAdBgNVHQ4E +FgQUJuolDwsyICik11oKjf8t3L1/VGUwbwYDVR0jBGgwZoAU8jXbNATapVXyvWkD +mbBi7OIVCMGhQ6RBMD8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UE +BwwHSGVybmRvbjERMA8GA1UECgwIQm9ndXMgQ0GCCQDokdYGkU/O8jAPBgNVHRMB +Af8EBTADAQH/MAsGA1UdDwQEAwIBhjBCBglghkgBhvhCAQ0ENRYzVGhpcyBjZXJ0 +aWZpY2F0ZSBjYW5ub3QgYmUgdHJ1c3RlZCBmb3IgYW55IHB1cnBvc2UuMBUGA1Ud +IAQOMAwwCgYIKwYBBQUHDQIwCgYDVR02BAMCAQIwgZEGCCsGAQUFBwEVBIGEMIGB +MFkGCyqGSIb3DQEJEAcDAwIF4DFGMESACyqGSIb3DQEJEAcEgTUwMwwXTEFXIERF +UEFSVE1FTlQgVVNFIE9OTFkMGEhVTUFOIFJFU09VUkNFUyBVU0UgT05MWTARBgsq +hkiG9w0BCRAHAgMCBPAwEQYLKoZIhvcNAQkQBwEDAgXgMAoGCCqGSM49BAMDA2cA +MGQCMBlIP4FWrNzWXR8OgfcvCLGPG+110EdsmwznIF6ThT1vbJYvYoSbBXTZ9OCh +/cCMMQIwJOySybHl/eLkNJh971DWF4mUQkt3WGBmZ+9Rg2cJTdat2ZjPKg101NuD +tkUyjGxfMIID1DCCA1qgAwIBAgIUUc1IQGJpeYQ0XwOS2ZmVEb3aeZ0wCgYIKoZI +zj0EAwMwZjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlZBMRAwDgYDVQQHEwdIZXJu +ZG9uMRAwDgYDVQQKEwdFeGFtcGxlMQwwCgYDVQQLEwNQQ0ExGDAWBgNVBAMTD3Bj +YS5leGFtcGxlLmNvbTAeFw0xOTExMDUyMjIwNDZaFw0yMDExMDQyMjIwNDZaMIGS +MQswCQYDVQQGEwJVUzELMAkGA1UECBMCVkExEDAOBgNVBAcTB0hlcm5kb24xEDAO +BgNVBAoTB0V4YW1wbGUxIjAgBgNVBAsTGUh1bWFuIFJlc291cmNlIERlcGFydG1l +bnQxDTALBgNVBAMTBEZyZWQxHzAdBgkqhkiG9w0BCQEWEGZyZWRAZXhhbXBsZS5j +b20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQObFslQ2EBP0xlDJ3sRnsNaqm/woQg +KpBispSxXxK5bWUVpfnWsZnjLWhtDuPcu1BcBlM2g7gwL/aw8nUSIK3D8Ja9rTUQ +QXc3zxnkcl8+8znNXHMGByRjPUH87C+TOrqjggGaMIIBljAdBgNVHQ4EFgQU5m71 +1OqFDNGRSWMOSzTXjpTLIFUwbwYDVR0jBGgwZoAUJuolDwsyICik11oKjf8t3L1/ +VGWhQ6RBMD8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UEBwwHSGVy +bmRvbjERMA8GA1UECgwIQm9ndXMgQ0GCCQCls1QoG7BuRjAPBgNVHRMBAf8EBTAD +AQH/MAsGA1UdDwQEAwIBhjBCBglghkgBhvhCAQ0ENRYzVGhpcyBjZXJ0aWZpY2F0 +ZSBjYW5ub3QgYmUgdHJ1c3RlZCBmb3IgYW55IHB1cnBvc2UuMBUGA1UdIAQOMAww +CgYIKwYBBQUHDQIwCgYDVR02BAMCAQIwfwYDVR0JBHgwdjBJBgNVBDcxQjBABgsq +hkiG9w0BCRAHAwMCBeAxLTArgAsqhkiG9w0BCRAHBIEcMBoMGEhVTUFOIFJFU09V +UkNFUyBVU0UgT05MWTApBglghkgBZQIBBUQxHAwaSHVtYW4gUmVzb3VyY2VzIERl +cGFydG1lbnQwCgYIKoZIzj0EAwMDaAAwZQIwVh/RypULFgPpAN0I7OvuMomRWnm/ +Hea3Hk8PtTRz2Zai8iYat7oeAmGVgMhSXy2jAjEAuJW4l/CFatBy4W/lZ7gS3weB +dBa5WEDIFFMC7GjGtCeLtXYqWfBnRdK26dOaHLB2MYIB7jCCAeoCAQEwfjBmMQsw +CQYDVQQGEwJVUzELMAkGA1UECBMCVkExEDAOBgNVBAcTB0hlcm5kb24xEDAOBgNV +BAoTB0V4YW1wbGUxDDAKBgNVBAsTA1BDQTEYMBYGA1UEAxMPcGNhLmV4YW1wbGUu +Y29tAhRRzUhAYml5hDRfA5LZmZURvdp5nTALBglghkgBZQMEAgKggeIwGgYJKoZI +hvcNAQkDMQ0GCyqGSIb3DQEJEAEXMBwGCSqGSIb3DQEJBTEPFw0xOTExMDgyMDA4 +MzFaMD8GCSqGSIb3DQEJBDEyBDCd5WyvIB0VdXgPBWPtI152MIJLg5o68IRimCXx +bVY0j3YyAKbi0egiZ/UunkyCfv0wZQYLKoZIhvcNAQkQAgIxVjFUAgEIBgsqhkiG +9w0BCRAHAzEtMCuACyqGSIb3DQEJEAcEgRwwGgwYSFVNQU4gUkVTT1VSQ0VTIFVT +RSBPTkxZExNCb2FndXMgUHJpdmFjeSBNYXJrMAoGCCqGSM49BAMDBGcwZQIwWkD7 +03QoNrKL5HJnuGJqvML1KlUXZDHnFpnJ+QMzXi8gocyfpRXWm6h0NjXieE0XAjEA +uuDSOoaUIz+G9aemAE0ldpo1c0avNGa7BtynUTHmwosD6Sjfj0epAg9OnMedOjbr +""" + + def testDerCodec(self): + layers = { } + layers.update(rfc5652.cmsContentTypesMap) + + getNextLayer = { + rfc5652.id_ct_contentInfo: lambda x: x['contentType'], + rfc5652.id_signedData: lambda x: x['encapContentInfo']['eContentType'], + rfc5083.id_ct_authEnvelopedData: lambda x: None + } + + getNextSubstrate = { + rfc5652.id_ct_contentInfo: lambda x: x['content'], + rfc5652.id_signedData: lambda x: x['encapContentInfo']['eContent'], + rfc5083.id_ct_authEnvelopedData: lambda x: None + } + + substrate = pem.readBase64fromText(self.pem_text) + + next_layer = rfc5652.id_ct_contentInfo + while next_layer: + asn1Object, rest = der_decode(substrate, asn1Spec=layers[next_layer]) + assert not rest + assert asn1Object.prettyPrint() + assert der_encode(asn1Object) == substrate + + if next_layer == rfc5652.id_signedData: + attrs = asn1Object['signerInfos'][0]['signedAttrs'] + certs = asn1Object['certificates'] + + substrate = getNextSubstrate[next_layer](asn1Object) + next_layer = getNextLayer[next_layer](asn1Object) + + spid = rfc3114.id_tsp_TEST_Whirlpool + catid = rfc3114.id_tsp_TEST_Whirlpool_Categories + conf = rfc3114.Whirlpool_SecurityClassification(value='whirlpool-confidential') + + assert catid in rfc5755.securityCategoryMap.keys() + assert rfc5755.id_at_clearance in rfc5280.certificateAttributesMap.keys() + assert rfc5280.id_ce_subjectDirectoryAttributes in rfc5280.certificateExtensionsMap.keys() + + security_label_okay = False + for attr in attrs: + if attr['attrType'] == rfc5035.id_aa_securityLabel: + esssl, rest = der_decode(attr['attrValues'][0], + asn1Spec=rfc5035.ESSSecurityLabel()) + assert not rest + assert esssl.prettyPrint() + assert der_encode(esssl) == attr['attrValues'][0] + + assert esssl['security-policy-identifier'] == spid + assert esssl['security-classification'] == conf + + for cat in esssl['security-categories']: + if cat['type'] == catid: + scv, rest = der_decode(cat['value'], + asn1Spec=rfc3114.SecurityCategoryValues()) + assert not rest + assert scv.prettyPrint() + assert der_encode(scv) == cat['value'] + for scv_str in scv: + assert 'USE ONLY' in scv_str + security_label_okay = True + + assert security_label_okay + + clearance_okay = False + for cert_choice in certs: + for extn in cert_choice['certificate']['tbsCertificate']['extensions']: + if extn['extnID'] == rfc5280.id_ce_subjectDirectoryAttributes: + ev, rest = der_decode(extn['extnValue'], + asn1Spec=rfc5280.certificateExtensionsMap[extn['extnID']]) + assert not rest + assert ev.prettyPrint() + assert der_encode(ev) == extn['extnValue'] + + for attr in ev: + if attr['type'] == rfc5755.id_at_clearance: + av, rest = der_decode(attr['values'][0], + asn1Spec=rfc5280.certificateAttributesMap[attr['type']]) + assert av['policyId'] == spid + for cat in av['securityCategories']: + assert cat['type'] == catid + scv, rest = der_decode(cat['value'], + asn1Spec=rfc5755.securityCategoryMap[cat['type']]) + assert not rest + assert scv.prettyPrint() + assert der_encode(scv) == cat['value'] + for scv_str in scv: + assert 'USE ONLY' in scv_str + clearance_okay = True + + assert clearance_okay + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + import sys + + result = unittest.TextTestRunner(verbosity=2).run(suite) + sys.exit(not result.wasSuccessful()) diff --git a/tests/test_rfc5755.py b/tests/test_rfc5755.py new file mode 100644 index 0000000..a41f0f9 --- /dev/null +++ b/tests/test_rfc5755.py @@ -0,0 +1,190 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# + +import sys + +from pyasn1.codec.der.decoder import decode as der_decode +from pyasn1.codec.der.encoder import encode as der_encode +from pyasn1.compat.octets import str2octs + +from pyasn1_modules import pem +from pyasn1_modules import rfc5280 +from pyasn1_modules import rfc5755 +from pyasn1_modules import rfc3114 + +try: + import unittest2 as unittest + +except ImportError: + import unittest + + +class AttributeCertificateTestCase(unittest.TestCase): + pem_text = """\ +MIIDBTCCAm4CAQEwgY+gUTBKpEgwRjEjMCEGA1UEAwwaQUNNRSBJbnRlcm1lZGlh +dGUgRUNEU0EgQ0ExCzAJBgNVBAYTAkZJMRIwEAYDVQQKDAlBQ01FIEx0ZC4CAx7N +WqE6pDgwNjETMBEGA1UEAwwKQUNNRSBFQ0RTQTELMAkGA1UEBhMCRkkxEjAQBgNV +BAoMCUFDTUUgTHRkLqA9MDukOTA3MRQwEgYDVQQDDAtleGFtcGxlLmNvbTELMAkG +A1UEBhMCRkkxEjAQBgNVBAoMCUFDTUUgTHRkLjANBgkqhkiG9w0BAQsFAAIEC63K +/jAiGA8yMDE2MDEwMTEyMDAwMFoYDzIwMTYwMzAxMTIwMDAwWjCB8jA8BggrBgEF +BQcKATEwMC6GC3VybjpzZXJ2aWNlpBUwEzERMA8GA1UEAwwIdXNlcm5hbWUECHBh +c3N3b3JkMDIGCCsGAQUFBwoCMSYwJIYLdXJuOnNlcnZpY2WkFTATMREwDwYDVQQD +DAh1c2VybmFtZTA1BggrBgEFBQcKAzEpMCegGKQWMBQxEjAQBgNVBAMMCUFDTUUg +THRkLjALDAlBQ01FIEx0ZC4wIAYIKwYBBQUHCgQxFDASMBAMBmdyb3VwMQwGZ3Jv +dXAyMCUGA1UESDEeMA2hC4YJdXJuOnJvbGUxMA2hC4YJdXJuOnJvbGUyMGowHwYD +VR0jBBgwFoAUgJCMhskAsEBzvklAX8yJBOXO500wCQYDVR04BAIFADA8BgNVHTcB +Af8EMjAwMB2gCoYIdXJuOnRlc3SgD4INKi5leGFtcGxlLmNvbTAPoA2GC3Vybjph +bm90aGVyMA0GCSqGSIb3DQEBCwUAA4GBACygfTs6TkPurZQTLufcE3B1H2707OXK +sJlwRpuodR2oJbunSHZ94jcJHs5dfbzFs6vNfVLlBiDBRieX4p+4JcQ2P44bkgyi +UTJu7g1b6C1liB3vO6yH5hOZicOAaKd+c/myuGb9uJ4n6y2oLNxnk/fDzpuZUe2h +Q4eikPk4LQey +""" + + def setUp(self): + self.asn1Spec = rfc5755.AttributeCertificate() + + 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 + + count = 0 + for attr in asn1Object['acinfo']['attributes']: + assert attr['type'] in rfc5280.certificateAttributesMap.keys() + av, rest = der_decode(attr['values'][0], + asn1Spec=rfc5280.certificateAttributesMap[attr['type']]) + assert not rest + assert av.prettyPrint() + assert der_encode(av) == attr['values'][0] + count += 1 + + assert count == 5 + + def testOpenTypes(self): + substrate = pem.readBase64fromText(self.pem_text) + asn1Object, rest = der_decode(substrate, + asn1Spec=self.asn1Spec, + decodeOpenTypes=True) + assert not rest + assert asn1Object.prettyPrint() + assert der_encode(asn1Object) == substrate + assert asn1Object['acinfo']['version'] == 1 + + count = 0 + for attr in asn1Object['acinfo']['attributes']: + assert attr['type'] in rfc5280.certificateAttributesMap.keys() + count += 1 + if attr['type'] == rfc5755.id_aca_authenticationInfo: + assert attr['values'][0]['authInfo'] == str2octs('password') + + assert count == 5 + +class CertificateWithClearanceTestCase(unittest.TestCase): + cert_pem_text = """\ +MIID1DCCA1qgAwIBAgIUUc1IQGJpeYQ0XwOS2ZmVEb3aeZ0wCgYIKoZIzj0EAwMw +ZjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlZBMRAwDgYDVQQHEwdIZXJuZG9uMRAw +DgYDVQQKEwdFeGFtcGxlMQwwCgYDVQQLEwNQQ0ExGDAWBgNVBAMTD3BjYS5leGFt +cGxlLmNvbTAeFw0xOTExMDUyMjIwNDZaFw0yMDExMDQyMjIwNDZaMIGSMQswCQYD +VQQGEwJVUzELMAkGA1UECBMCVkExEDAOBgNVBAcTB0hlcm5kb24xEDAOBgNVBAoT +B0V4YW1wbGUxIjAgBgNVBAsTGUh1bWFuIFJlc291cmNlIERlcGFydG1lbnQxDTAL +BgNVBAMTBEZyZWQxHzAdBgkqhkiG9w0BCQEWEGZyZWRAZXhhbXBsZS5jb20wdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAAQObFslQ2EBP0xlDJ3sRnsNaqm/woQgKpBispSx +XxK5bWUVpfnWsZnjLWhtDuPcu1BcBlM2g7gwL/aw8nUSIK3D8Ja9rTUQQXc3zxnk +cl8+8znNXHMGByRjPUH87C+TOrqjggGaMIIBljAdBgNVHQ4EFgQU5m711OqFDNGR +SWMOSzTXjpTLIFUwbwYDVR0jBGgwZoAUJuolDwsyICik11oKjf8t3L1/VGWhQ6RB +MD8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UEBwwHSGVybmRvbjER +MA8GA1UECgwIQm9ndXMgQ0GCCQCls1QoG7BuRjAPBgNVHRMBAf8EBTADAQH/MAsG +A1UdDwQEAwIBhjBCBglghkgBhvhCAQ0ENRYzVGhpcyBjZXJ0aWZpY2F0ZSBjYW5u +b3QgYmUgdHJ1c3RlZCBmb3IgYW55IHB1cnBvc2UuMBUGA1UdIAQOMAwwCgYIKwYB +BQUHDQIwCgYDVR02BAMCAQIwfwYDVR0JBHgwdjBJBgNVBDcxQjBABgsqhkiG9w0B +CRAHAwMCBeAxLTArgAsqhkiG9w0BCRAHBIEcMBoMGEhVTUFOIFJFU09VUkNFUyBV +U0UgT05MWTApBglghkgBZQIBBUQxHAwaSHVtYW4gUmVzb3VyY2VzIERlcGFydG1l +bnQwCgYIKoZIzj0EAwMDaAAwZQIwVh/RypULFgPpAN0I7OvuMomRWnm/Hea3Hk8P +tTRz2Zai8iYat7oeAmGVgMhSXy2jAjEAuJW4l/CFatBy4W/lZ7gS3weBdBa5WEDI +FFMC7GjGtCeLtXYqWfBnRdK26dOaHLB2 +""" + + def setUp(self): + self.asn1Spec = rfc5280.Certificate() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.cert_pem_text) + asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert der_encode(asn1Object) == substrate + + clearance_found = False + for extn in asn1Object['tbsCertificate']['extensions']: + if extn['extnID'] == rfc5280.id_ce_subjectDirectoryAttributes: + assert extn['extnID'] in rfc5280.certificateExtensionsMap.keys() + ev, rest = der_decode(extn['extnValue'], + asn1Spec=rfc5280.certificateExtensionsMap[extn['extnID']]) + assert not rest + assert ev.prettyPrint() + assert der_encode(ev) == extn['extnValue'] + + for attr in ev: + if attr['type'] == rfc5755.id_at_clearance: + assert attr['type'] in rfc5280.certificateAttributesMap.keys() + av, rest = der_decode(attr['values'][0], + asn1Spec=rfc5280.certificateAttributesMap[attr['type']]) + assert av['policyId'] == rfc3114.id_tsp_TEST_Whirlpool + for cat in av['securityCategories']: + assert cat['type'] == rfc3114.id_tsp_TEST_Whirlpool_Categories + assert cat['type'] in rfc5755.securityCategoryMap.keys() + catv, rest = der_decode(cat['value'], + asn1Spec=rfc5755.securityCategoryMap[cat['type']]) + assert u'USE ONLY' in catv[0] + clearance_found = True + + assert clearance_found + + def testOpenTypes(self): + substrate = pem.readBase64fromText(self.cert_pem_text) + asn1Object, rest = der_decode(substrate, + asn1Spec=self.asn1Spec, + decodeOpenTypes=True) + assert not rest + assert asn1Object.prettyPrint() + assert der_encode(asn1Object) == substrate + + clearance_found = False + for extn in asn1Object['tbsCertificate']['extensions']: + if extn['extnID'] == rfc5280.id_ce_subjectDirectoryAttributes: + assert extn['extnID'] in rfc5280.certificateExtensionsMap.keys() + ev, rest = der_decode(extn['extnValue'], + asn1Spec=rfc5280.certificateExtensionsMap[extn['extnID']], + decodeOpenTypes=True) + assert not rest + assert ev.prettyPrint() + assert der_encode(ev) == extn['extnValue'] + + for attr in ev: + if attr['type'] == rfc5755.id_at_clearance: + spid = rfc3114.id_tsp_TEST_Whirlpool + catid = rfc3114.id_tsp_TEST_Whirlpool_Categories + assert attr['values'][0]['policyId'] == spid + for cat in attr['values'][0]['securityCategories']: + assert cat['type'] == catid + assert u'USE ONLY' in cat['value'][0] + clearance_found = True + + assert clearance_found + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + import sys + + result = unittest.TextTestRunner(verbosity=2).run(suite) + sys.exit(not result.wasSuccessful()) diff --git a/tests/test_rfc5913.py b/tests/test_rfc5913.py new file mode 100644 index 0000000..f140d92 --- /dev/null +++ b/tests/test_rfc5913.py @@ -0,0 +1,114 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# + +import sys + +from pyasn1.codec.der.decoder import decode as der_decode +from pyasn1.codec.der.encoder import encode as der_encode + +from pyasn1_modules import pem +from pyasn1_modules import rfc5280 +from pyasn1_modules import rfc5913 +from pyasn1_modules import rfc5755 +from pyasn1_modules import rfc3114 + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class ClearanceTestCase(unittest.TestCase): + cert_pem_text = """\ +MIIDhzCCAw6gAwIBAgIJAKWzVCgbsG5GMAoGCCqGSM49BAMDMD8xCzAJBgNVBAYT +AlVTMQswCQYDVQQIDAJWQTEQMA4GA1UEBwwHSGVybmRvbjERMA8GA1UECgwIQm9n +dXMgQ0EwHhcNMTkxMTAyMTg0MjE4WhcNMjAxMTAxMTg0MjE4WjBmMQswCQYDVQQG +EwJVUzELMAkGA1UECBMCVkExEDAOBgNVBAcTB0hlcm5kb24xEDAOBgNVBAoTB0V4 +YW1wbGUxDDAKBgNVBAsTA1BDQTEYMBYGA1UEAxMPcGNhLmV4YW1wbGUuY29tMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEPf5vbgAqbE5dn6wbiCx4sCCcn1BKSrHmCfiW +C9QLSGVNGHifQwPt9odGXjRiQ7QwpZ2wRD6Z91v+fk85XXLE3kJQCQdPIHFUY5EM +pvS7T6u6xrmwnlVpUURPTOxfc55Oo4IBrTCCAakwHQYDVR0OBBYEFCbqJQ8LMiAo +pNdaCo3/Ldy9f1RlMG8GA1UdIwRoMGaAFPI12zQE2qVV8r1pA5mwYuziFQjBoUOk +QTA/MQswCQYDVQQGEwJVUzELMAkGA1UECAwCVkExEDAOBgNVBAcMB0hlcm5kb24x +ETAPBgNVBAoMCEJvZ3VzIENBggkA6JHWBpFPzvIwDwYDVR0TAQH/BAUwAwEB/zAL +BgNVHQ8EBAMCAYYwQgYJYIZIAYb4QgENBDUWM1RoaXMgY2VydGlmaWNhdGUgY2Fu +bm90IGJlIHRydXN0ZWQgZm9yIGFueSBwdXJwb3NlLjAVBgNVHSAEDjAMMAoGCCsG +AQUFBw0CMAoGA1UdNgQDAgECMIGRBggrBgEFBQcBFQSBhDCBgTBZBgsqhkiG9w0B +CRAHAwMCBeAxRjBEgAsqhkiG9w0BCRAHBIE1MDMMF0xBVyBERVBBUlRNRU5UIFVT +RSBPTkxZDBhIVU1BTiBSRVNPVVJDRVMgVVNFIE9OTFkwEQYLKoZIhvcNAQkQBwID +AgTwMBEGCyqGSIb3DQEJEAcBAwIF4DAKBggqhkjOPQQDAwNnADBkAjAZSD+BVqzc +1l0fDoH3LwixjxvtddBHbJsM5yBek4U9b2yWL2KEmwV02fTgof3AjDECMCTsksmx +5f3i5DSYfe9Q1heJlEJLd1hgZmfvUYNnCU3WrdmYzyoNdNTbg7ZFMoxsXw== +""" + + def setUp(self): + self.asn1Spec = rfc5280.Certificate() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.cert_pem_text) + asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert der_encode(asn1Object) == substrate + + cat_value_found = False + for extn in asn1Object['tbsCertificate']['extensions']: + if extn['extnID'] == rfc5913.id_pe_clearanceConstraints: + assert extn['extnID'] in rfc5280.certificateExtensionsMap.keys() + ev, rest = der_decode(extn['extnValue'], + asn1Spec=rfc5280.certificateExtensionsMap[extn['extnID']]) + assert not rest + assert ev.prettyPrint() + assert der_encode(ev) == extn['extnValue'] + + for c in ev: + if c['policyId'] == rfc3114.id_tsp_TEST_Whirlpool: + for sc in c['securityCategories']: + assert sc['type'] in rfc5755.securityCategoryMap.keys() + scv, rest = der_decode(sc['value'], + asn1Spec=rfc5755.securityCategoryMap[sc['type']]) + for cat in scv: + assert u'USE ONLY' in cat + cat_value_found = True + + assert cat_value_found + + def testOpenTypes(self): + substrate = pem.readBase64fromText(self.cert_pem_text) + asn1Object, rest = der_decode(substrate, + asn1Spec=self.asn1Spec, + decodeOpenTypes=True) + assert not rest + assert asn1Object.prettyPrint() + assert der_encode(asn1Object) == substrate + + cat_value_found = False + for extn in asn1Object['tbsCertificate']['extensions']: + if extn['extnID'] == rfc5913.id_pe_clearanceConstraints: + assert extn['extnID'] in rfc5280.certificateExtensionsMap.keys() + ev, rest = der_decode(extn['extnValue'], + asn1Spec=rfc5280.certificateExtensionsMap[extn['extnID']], + decodeOpenTypes=True) + assert not rest + assert ev.prettyPrint() + assert der_encode(ev) == extn['extnValue'] + + for c in ev: + if c['policyId'] == rfc3114.id_tsp_TEST_Whirlpool: + for sc in c['securityCategories']: + assert sc['type'] in rfc5755.securityCategoryMap.keys() + for cat in sc['value']: + assert u'USE ONLY' in cat + cat_value_found = True + + assert cat_value_found + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/tests/test_rfc5917.py b/tests/test_rfc5917.py new file mode 100644 index 0000000..459895d --- /dev/null +++ b/tests/test_rfc5917.py @@ -0,0 +1,112 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# + +import sys + +from pyasn1.codec.der.decoder import decode as der_decode +from pyasn1.codec.der.encoder import encode as der_encode + +from pyasn1_modules import pem +from pyasn1_modules import rfc5280 +from pyasn1_modules import rfc5917 + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class ClearanceSponsorTestCase(unittest.TestCase): + cert_pem_text = """\ +MIID1DCCA1qgAwIBAgIUUc1IQGJpeYQ0XwOS2ZmVEb3aeZ0wCgYIKoZIzj0EAwMw +ZjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlZBMRAwDgYDVQQHEwdIZXJuZG9uMRAw +DgYDVQQKEwdFeGFtcGxlMQwwCgYDVQQLEwNQQ0ExGDAWBgNVBAMTD3BjYS5leGFt +cGxlLmNvbTAeFw0xOTExMDUyMjIwNDZaFw0yMDExMDQyMjIwNDZaMIGSMQswCQYD +VQQGEwJVUzELMAkGA1UECBMCVkExEDAOBgNVBAcTB0hlcm5kb24xEDAOBgNVBAoT +B0V4YW1wbGUxIjAgBgNVBAsTGUh1bWFuIFJlc291cmNlIERlcGFydG1lbnQxDTAL +BgNVBAMTBEZyZWQxHzAdBgkqhkiG9w0BCQEWEGZyZWRAZXhhbXBsZS5jb20wdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAAQObFslQ2EBP0xlDJ3sRnsNaqm/woQgKpBispSx +XxK5bWUVpfnWsZnjLWhtDuPcu1BcBlM2g7gwL/aw8nUSIK3D8Ja9rTUQQXc3zxnk +cl8+8znNXHMGByRjPUH87C+TOrqjggGaMIIBljAdBgNVHQ4EFgQU5m711OqFDNGR +SWMOSzTXjpTLIFUwbwYDVR0jBGgwZoAUJuolDwsyICik11oKjf8t3L1/VGWhQ6RB +MD8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UEBwwHSGVybmRvbjER +MA8GA1UECgwIQm9ndXMgQ0GCCQCls1QoG7BuRjAPBgNVHRMBAf8EBTADAQH/MAsG +A1UdDwQEAwIBhjBCBglghkgBhvhCAQ0ENRYzVGhpcyBjZXJ0aWZpY2F0ZSBjYW5u +b3QgYmUgdHJ1c3RlZCBmb3IgYW55IHB1cnBvc2UuMBUGA1UdIAQOMAwwCgYIKwYB +BQUHDQIwCgYDVR02BAMCAQIwfwYDVR0JBHgwdjBJBgNVBDcxQjBABgsqhkiG9w0B +CRAHAwMCBeAxLTArgAsqhkiG9w0BCRAHBIEcMBoMGEhVTUFOIFJFU09VUkNFUyBV +U0UgT05MWTApBglghkgBZQIBBUQxHAwaSHVtYW4gUmVzb3VyY2VzIERlcGFydG1l +bnQwCgYIKoZIzj0EAwMDaAAwZQIwVh/RypULFgPpAN0I7OvuMomRWnm/Hea3Hk8P +tTRz2Zai8iYat7oeAmGVgMhSXy2jAjEAuJW4l/CFatBy4W/lZ7gS3weBdBa5WEDI +FFMC7GjGtCeLtXYqWfBnRdK26dOaHLB2 +""" + + def setUp(self): + self.asn1Spec = rfc5280.Certificate() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.cert_pem_text) + asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert der_encode(asn1Object) == substrate + + cs = rfc5917.DirectoryString() + cs['utf8String'] = u'Human Resources Department' + encoded_cs = der_encode(cs) + + clearance_sponsor_found = False + for extn in asn1Object['tbsCertificate']['extensions']: + if extn['extnID'] == rfc5280.id_ce_subjectDirectoryAttributes: + assert extn['extnID'] in rfc5280.certificateExtensionsMap.keys() + ev, rest = der_decode(extn['extnValue'], + asn1Spec=rfc5280.certificateExtensionsMap[extn['extnID']]) + assert not rest + assert ev.prettyPrint() + assert der_encode(ev) == extn['extnValue'] + + for attr in ev: + if attr['type'] == rfc5917.id_clearanceSponsor: + assert attr['values'][0] == encoded_cs + clearance_sponsor_found = True + + assert clearance_sponsor_found + + def testOpenTypes(self): + substrate = pem.readBase64fromText(self.cert_pem_text) + asn1Object, rest = der_decode(substrate, + asn1Spec=self.asn1Spec, + decodeOpenTypes=True) + assert not rest + assert asn1Object.prettyPrint() + assert der_encode(asn1Object) == substrate + + clearance_sponsor_found = False + for extn in asn1Object['tbsCertificate']['extensions']: + if extn['extnID'] == rfc5280.id_ce_subjectDirectoryAttributes: + assert extn['extnID'] in rfc5280.certificateExtensionsMap.keys() + ev, rest = der_decode(extn['extnValue'], + asn1Spec=rfc5280.certificateExtensionsMap[extn['extnID']], + decodeOpenTypes=True) + assert not rest + assert ev.prettyPrint() + assert der_encode(ev) == extn['extnValue'] + + for attr in ev: + if attr['type'] == rfc5917.id_clearanceSponsor: + hrd = u'Human Resources Department' + assert attr['values'][0]['utf8String'] == hrd + clearance_sponsor_found = True + + assert clearance_sponsor_found + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) |