diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2015-04-02 17:18:23 -0500 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2015-04-02 17:18:23 -0500 |
commit | c053129791404f5f03df2c2243878f08352fb88d (patch) | |
tree | d93bfd399e978e237af4c3a4b874b697a2f45a5f | |
parent | 7209d3e2071d4e66e1da0c4c99e71c9bf5601b1a (diff) | |
parent | 738407ba87472f7f474c164e2fd33ab037bab93f (diff) | |
download | cryptography-c053129791404f5f03df2c2243878f08352fb88d.tar.gz cryptography-c053129791404f5f03df2c2243878f08352fb88d.tar.bz2 cryptography-c053129791404f5f03df2c2243878f08352fb88d.zip |
Merge pull request #1802 from reaperhulk/x509-keyusage
add KeyUsage extension
-rw-r--r-- | docs/x509.rst | 97 | ||||
-rw-r--r-- | src/cryptography/x509.py | 47 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 97 |
3 files changed, 241 insertions, 0 deletions
diff --git a/docs/x509.rst b/docs/x509.rst index af249449..afc9620a 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -447,6 +447,98 @@ X.509 Extensions Returns an instance of the extension type corresponding to the OID. +.. class:: KeyUsage + + .. versionadded:: 0.9 + + The key usage extension defines the purpose of the key contained in the + certificate. The usage restriction might be employed when a key that could + be used for more than one operation is to be restricted. It corresponds to + :data:`OID_KEY_USAGE`. + + .. attribute:: digital_signature + + :type: bool + + This purpose is set to true when the subject public key is used for verifying + digital signatures, other than signatures on certificates + (``key_cert_sign``) and CRLs (``crl_sign``). + + .. attribute:: content_commitment + + :type: bool + + This purpose is set to true when the subject public key is used for verifying + digital signatures, other than signatures on certificates + (``key_cert_sign``) and CRLs (``crl_sign``). It is used to provide a + non-repudiation service that protects against the signing entity + falsely denying some action. In the case of later conflict, a + reliable third party may determine the authenticity of the signed + data. This was called ``non_repudiation`` in older revisions of the + X.509 specification. + + .. attribute:: key_encipherment + + :type: bool + + This purpose is set to true when the subject public key is used for + enciphering private or secret keys. + + .. attribute:: data_encipherment + + :type: bool + + This purpose is set to true when the subject public key is used for + directly enciphering raw user data without the use of an intermediate + symmetric cipher. + + .. attribute:: key_agreement + + :type: bool + + This purpose is set to true when the subject public key is used for key + agreement. For example, when a Diffie-Hellman key is to be used for + key management, then this purpose is set to true. + + .. attribute:: key_cert_sign + + :type: bool + + This purpose is set to true when the subject public key is used for + verifying signatures on public key certificates. If this purpose is set + to true then ``ca`` must be true in the :class:`BasicConstraints` + extension. + + .. attribute:: crl_sign + + :type: bool + + This purpose is set to true when the subject public key is used for + verifying signatures on certificate revocation lists. + + .. attribute:: encipher_only + + :type: bool + + When this purposes is set to true and the ``key_agreement`` purpose is + also set, the subject public key may be used only for enciphering data + while performing key agreement. + + :raises ValueError: This is raised if accessed when ``key_agreement`` + is false. + + .. attribute:: decipher_only + + :type: bool + + When this purposes is set to true and the ``key_agreement`` purpose is + also set, the subject public key may be used only for deciphering data + while performing key agreement. + + :raises ValueError: This is raised if accessed when ``key_agreement`` + is false. + + .. class:: BasicConstraints .. versionadded:: 0.9 @@ -687,6 +779,11 @@ Extension OIDs Corresponds to the dotted string ``"2.5.29.19"``. The identifier for the :class:`BasicConstraints` extension type. +.. data:: OID_KEY_USAGE + + Corresponds to the dotted string ``"2.5.29.15"``. The identifier for the + :class:`KeyUsage` extension type. + Exceptions ~~~~~~~~~~ diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 791d1ef0..63c8767d 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -266,6 +266,53 @@ class BasicConstraints(object): "path_length={0.path_length})>").format(self) +class KeyUsage(object): + def __init__(self, digital_signature, content_commitment, key_encipherment, + data_encipherment, key_agreement, key_cert_sign, crl_sign, + encipher_only, decipher_only): + if not key_agreement and (encipher_only or decipher_only): + raise ValueError( + "encipher_only and decipher_only can only be true when " + "key_agreement is true" + ) + + self._digital_signature = digital_signature + self._content_commitment = content_commitment + self._key_encipherment = key_encipherment + self._data_encipherment = data_encipherment + self._key_agreement = key_agreement + self._key_cert_sign = key_cert_sign + self._crl_sign = crl_sign + self._encipher_only = encipher_only + self._decipher_only = decipher_only + + digital_signature = utils.read_only_property("_digital_signature") + content_commitment = utils.read_only_property("_content_commitment") + key_encipherment = utils.read_only_property("_key_encipherment") + data_encipherment = utils.read_only_property("_data_encipherment") + key_agreement = utils.read_only_property("_key_agreement") + key_cert_sign = utils.read_only_property("_key_cert_sign") + crl_sign = utils.read_only_property("_crl_sign") + + @property + def encipher_only(self): + if not self.key_agreement: + raise ValueError( + "encipher_only is undefined unless key_agreement is true" + ) + else: + return self._encipher_only + + @property + def decipher_only(self): + if not self.key_agreement: + raise ValueError( + "decipher_only is undefined unless key_agreement is true" + ) + else: + return self._decipher_only + + OID_COMMON_NAME = ObjectIdentifier("2.5.4.3") OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6") OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7") diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 87580a0d..7447ac4b 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -35,6 +35,103 @@ class TestExtension(object): ) +class TestKeyUsage(object): + def test_key_agreement_false_encipher_decipher_true(self): + with pytest.raises(ValueError): + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=True, + decipher_only=False + ) + + with pytest.raises(ValueError): + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=True, + decipher_only=True + ) + + with pytest.raises(ValueError): + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + + def test_properties_key_agreement_true(self): + ku = x509.KeyUsage( + digital_signature=True, + content_commitment=True, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert ku.digital_signature is True + assert ku.content_commitment is True + assert ku.key_encipherment is False + assert ku.data_encipherment is False + assert ku.key_agreement is False + assert ku.key_cert_sign is True + assert ku.crl_sign is False + + def test_key_agreement_true_properties(self): + ku = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=True + ) + assert ku.key_agreement is True + assert ku.encipher_only is False + assert ku.decipher_only is True + + def test_key_agreement_false_properties(self): + ku = x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=False, + crl_sign=False, + encipher_only=False, + decipher_only=False + ) + assert ku.key_agreement is False + with pytest.raises(ValueError): + ku.encipher_only + + with pytest.raises(ValueError): + ku.decipher_only + + class TestBasicConstraints(object): def test_ca_not_boolean(self): with pytest.raises(TypeError): |