Merge pull request #1426 from alex/read-only-property

Added a utility for implementing a read only property of another field
diff --git a/cryptography/hazmat/backends/commoncrypto/ciphers.py b/cryptography/hazmat/backends/commoncrypto/ciphers.py
index 6d3ba86..d94746c 100644
--- a/cryptography/hazmat/backends/commoncrypto/ciphers.py
+++ b/cryptography/hazmat/backends/commoncrypto/ciphers.py
@@ -198,6 +198,4 @@
         )
         self._backend._check_cipher_response(res)
 
-    @property
-    def tag(self):
-        return self._tag
+    tag = utils.read_only_property("_tag")
diff --git a/cryptography/hazmat/backends/openssl/ciphers.py b/cryptography/hazmat/backends/openssl/ciphers.py
index d37bb01..4ec2ac8 100644
--- a/cryptography/hazmat/backends/openssl/ciphers.py
+++ b/cryptography/hazmat/backends/openssl/ciphers.py
@@ -187,9 +187,7 @@
         )
         assert res != 0
 
-    @property
-    def tag(self):
-        return self._tag
+    tag = utils.read_only_property("_tag")
 
 
 @utils.register_interface(interfaces.CipherContext)
diff --git a/cryptography/hazmat/backends/openssl/dsa.py b/cryptography/hazmat/backends/openssl/dsa.py
index 3fb67a5..2298e7d 100644
--- a/cryptography/hazmat/backends/openssl/dsa.py
+++ b/cryptography/hazmat/backends/openssl/dsa.py
@@ -129,9 +129,7 @@
         self._dsa_cdata = dsa_cdata
         self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p)
 
-    @property
-    def key_size(self):
-        return self._key_size
+    key_size = utils.read_only_property("_key_size")
 
     def signer(self, algorithm):
         return _DSASignatureContext(self._backend, self, algorithm)
@@ -180,9 +178,7 @@
         self._dsa_cdata = dsa_cdata
         self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p)
 
-    @property
-    def key_size(self):
-        return self._key_size
+    key_size = utils.read_only_property("_key_size")
 
     def verifier(self, signature, algorithm):
         return _DSAVerificationContext(
diff --git a/cryptography/hazmat/backends/openssl/ec.py b/cryptography/hazmat/backends/openssl/ec.py
index 7798c3d..13b0ddb 100644
--- a/cryptography/hazmat/backends/openssl/ec.py
+++ b/cryptography/hazmat/backends/openssl/ec.py
@@ -146,9 +146,7 @@
         sn = _ec_key_curve_sn(backend, ec_key_cdata)
         self._curve = _sn_to_elliptic_curve(backend, sn)
 
-    @property
-    def curve(self):
-        return self._curve
+    curve = utils.read_only_property("_curve")
 
     def signer(self, signature_algorithm):
         if isinstance(signature_algorithm, ec.ECDSA):
@@ -200,9 +198,7 @@
         sn = _ec_key_curve_sn(backend, ec_key_cdata)
         self._curve = _sn_to_elliptic_curve(backend, sn)
 
-    @property
-    def curve(self):
-        return self._curve
+    curve = utils.read_only_property("_curve")
 
     def verifier(self, signature, signature_algorithm):
         if isinstance(signature_algorithm, ec.ECDSA):
diff --git a/cryptography/hazmat/backends/openssl/rsa.py b/cryptography/hazmat/backends/openssl/rsa.py
index 7312fcb..0a2a7f9 100644
--- a/cryptography/hazmat/backends/openssl/rsa.py
+++ b/cryptography/hazmat/backends/openssl/rsa.py
@@ -532,9 +532,7 @@
 
         self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
 
-    @property
-    def key_size(self):
-        return self._key_size
+    key_size = utils.read_only_property("_key_size")
 
     def signer(self, padding, algorithm):
         return _RSASignatureContext(self._backend, self, padding, algorithm)
@@ -588,9 +586,7 @@
 
         self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
 
-    @property
-    def key_size(self):
-        return self._key_size
+    key_size = utils.read_only_property("_key_size")
 
     def verifier(self, signature, padding, algorithm):
         return _RSAVerificationContext(
diff --git a/cryptography/hazmat/primitives/asymmetric/dsa.py b/cryptography/hazmat/primitives/asymmetric/dsa.py
index 9726586..83e0137 100644
--- a/cryptography/hazmat/primitives/asymmetric/dsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/dsa.py
@@ -61,17 +61,9 @@
         self._q = q
         self._g = g
 
-    @property
-    def p(self):
-        return self._p
-
-    @property
-    def q(self):
-        return self._q
-
-    @property
-    def g(self):
-        return self._g
+    p = utils.read_only_property("_p")
+    q = utils.read_only_property("_q")
+    g = utils.read_only_property("_g")
 
     def parameters(self, backend):
         return backend.load_dsa_parameter_numbers(self)
@@ -90,13 +82,8 @@
         self._y = y
         self._parameter_numbers = parameter_numbers
 
-    @property
-    def y(self):
-        return self._y
-
-    @property
-    def parameter_numbers(self):
-        return self._parameter_numbers
+    y = utils.read_only_property("_y")
+    parameter_numbers = utils.read_only_property("_parameter_numbers")
 
     def public_key(self, backend):
         return backend.load_dsa_public_numbers(self)
@@ -114,13 +101,8 @@
         self._public_numbers = public_numbers
         self._x = x
 
-    @property
-    def x(self):
-        return self._x
-
-    @property
-    def public_numbers(self):
-        return self._public_numbers
+    x = utils.read_only_property("_x")
+    public_numbers = utils.read_only_property("_public_numbers")
 
     def private_key(self, backend):
         return backend.load_dsa_private_numbers(self)
diff --git a/cryptography/hazmat/primitives/asymmetric/ec.py b/cryptography/hazmat/primitives/asymmetric/ec.py
index 6dcf39c..b27d045 100644
--- a/cryptography/hazmat/primitives/asymmetric/ec.py
+++ b/cryptography/hazmat/primitives/asymmetric/ec.py
@@ -213,9 +213,7 @@
     def __init__(self, algorithm):
         self._algorithm = algorithm
 
-    @property
-    def algorithm(self):
-        return self._algorithm
+    algorithm = utils.read_only_property("_algorithm")
 
 
 def generate_private_key(curve, backend):
@@ -243,17 +241,9 @@
         except AttributeError:
             return backend.elliptic_curve_public_key_from_numbers(self)
 
-    @property
-    def curve(self):
-        return self._curve
-
-    @property
-    def x(self):
-        return self._x
-
-    @property
-    def y(self):
-        return self._y
+    curve = utils.read_only_property("_curve")
+    x = utils.read_only_property("_x")
+    y = utils.read_only_property("_y")
 
 
 class EllipticCurvePrivateNumbers(object):
@@ -276,10 +266,5 @@
         except AttributeError:
             return backend.elliptic_curve_private_key_from_numbers(self)
 
-    @property
-    def private_value(self):
-        return self._private_value
-
-    @property
-    def public_numbers(self):
-        return self._public_numbers
+    private_value = utils.read_only_property("_private_value")
+    public_numbers = utils.read_only_property("_public_numbers")
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
index c192811..db38ed5 100644
--- a/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -15,6 +15,7 @@
 
 import six
 
+from cryptography import utils
 from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
 from cryptography.hazmat.backends.interfaces import RSABackend
 
@@ -157,33 +158,13 @@
         self._iqmp = iqmp
         self._public_numbers = public_numbers
 
-    @property
-    def p(self):
-        return self._p
-
-    @property
-    def q(self):
-        return self._q
-
-    @property
-    def d(self):
-        return self._d
-
-    @property
-    def dmp1(self):
-        return self._dmp1
-
-    @property
-    def dmq1(self):
-        return self._dmq1
-
-    @property
-    def iqmp(self):
-        return self._iqmp
-
-    @property
-    def public_numbers(self):
-        return self._public_numbers
+    p = utils.read_only_property("_p")
+    q = utils.read_only_property("_q")
+    d = utils.read_only_property("_d")
+    dmp1 = utils.read_only_property("_dmp1")
+    dmq1 = utils.read_only_property("_dmq1")
+    iqmp = utils.read_only_property("_iqmp")
+    public_numbers = utils.read_only_property("_public_numbers")
 
     def private_key(self, backend):
         return backend.load_rsa_private_numbers(self)
@@ -200,13 +181,8 @@
         self._e = e
         self._n = n
 
-    @property
-    def e(self):
-        return self._e
-
-    @property
-    def n(self):
-        return self._n
+    e = utils.read_only_property("_e")
+    n = utils.read_only_property("_n")
 
     def public_key(self, backend):
         return backend.load_rsa_public_numbers(self)
diff --git a/cryptography/utils.py b/cryptography/utils.py
index 55187c3..1deb3d1 100644
--- a/cryptography/utils.py
+++ b/cryptography/utils.py
@@ -26,6 +26,10 @@
     return register_decorator
 
 
+def read_only_property(name):
+    return property(lambda self: getattr(self, name))
+
+
 def bit_length(x):
     if sys.version_info >= (2, 7):
         return x.bit_length()