diff --git a/PKG-INFO b/PKG-INFO
index a97b885dbb6ac74bb8697d848cb7f7654ba288c7..f9bcafd17410f37d9819e23c4137799b7c4f14f0 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: swh.model
-Version: 0.0.40
+Version: 0.0.41
 Summary: Software Heritage data model
 Home-page: https://forge.softwareheritage.org/diffusion/DMOD/
 Author: Software Heritage developers
diff --git a/swh.model.egg-info/PKG-INFO b/swh.model.egg-info/PKG-INFO
index a97b885dbb6ac74bb8697d848cb7f7654ba288c7..f9bcafd17410f37d9819e23c4137799b7c4f14f0 100644
--- a/swh.model.egg-info/PKG-INFO
+++ b/swh.model.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: swh.model
-Version: 0.0.40
+Version: 0.0.41
 Summary: Software Heritage data model
 Home-page: https://forge.softwareheritage.org/diffusion/DMOD/
 Author: Software Heritage developers
diff --git a/swh/model/hypothesis_strategies.py b/swh/model/hypothesis_strategies.py
index 1b99957a737030dab80f3f01f204a925e6d2621f..e20f4ea114d097f0d728b3c672cabe698d3e219f 100644
--- a/swh/model/hypothesis_strategies.py
+++ b/swh/model/hypothesis_strategies.py
@@ -132,7 +132,7 @@ def contents(draw):
     (status, data, reason) = draw(one_of(
         tuples(just('visible'), binary(), none()),
         tuples(just('absent'), none(), pgsql_text()),
-        tuples(just('hidden'), none(), none()),
+        tuples(just('hidden'), binary(), none()),
     ))
 
     return draw(builds(
diff --git a/swh/model/model.py b/swh/model/model.py
index 5f2d960a8a7bf6be2dc943c27ebd5deb6c74a287..36f8ef3f1838fcf0ea8c632962cde906ee7db5bb 100644
--- a/swh/model/model.py
+++ b/swh/model/model.py
@@ -11,6 +11,7 @@ import attr
 import dateutil.parser
 
 from .identifiers import normalize_timestamp
+from .hashutil import DEFAULT_ALGORITHMS
 
 SHA1_SIZE = 20
 
@@ -335,11 +336,16 @@ class Content(BaseModel):
                    default=None,
                    validator=attr.validators.optional([]))
 
+    ctime = attr.ib(type=Optional[datetime.datetime],
+                    default=None)
+
     @length.validator
     def check_length(self, attribute, value):
         """Checks the length is positive."""
-        if value < 0:
-            raise ValueError('Length must be positive.')
+        if self.status == 'absent' and value < -1:
+            raise ValueError('Length must be positive or -1.')
+        elif self.status != 'absent' and value < 0:
+            raise ValueError('Length must be positive, unless status=absent.')
 
     @reason.validator
     def check_reason(self, attribute, value):
@@ -353,8 +359,12 @@ class Content(BaseModel):
 
     def to_dict(self):
         content = attr.asdict(self)
-        if content['data'] is None:
-            del content['data']
-        if content['reason'] is None:
-            del content['reason']
+        for field in ('data', 'reason', 'ctime'):
+            if content[field] is None:
+                del content[field]
         return content
+
+    def get_hash(self, hash_name):
+        if hash_name not in DEFAULT_ALGORITHMS:
+            raise ValueError('{} is not a valid hash name.'.format(hash_name))
+        return getattr(self, hash_name)
diff --git a/swh/model/tests/test_hypothesis_strategies.py b/swh/model/tests/test_hypothesis_strategies.py
index 3e69ab9b93c8963c84f45023a0f89d9d61b3ad62..09c21d8119359c4d3849dc23d8dcb10bb3de1bc8 100644
--- a/swh/model/tests/test_hypothesis_strategies.py
+++ b/swh/model/tests/test_hypothesis_strategies.py
@@ -49,7 +49,7 @@ def test_dicts_generation(obj_type_and_obj):
                 set(DEFAULT_ALGORITHMS) | {'length', 'status', 'reason'}
         elif object_['status'] == 'hidden':
             assert set(object_) == \
-                set(DEFAULT_ALGORITHMS) | {'length', 'status'}
+                set(DEFAULT_ALGORITHMS) | {'length', 'status', 'data'}
         else:
             assert False, object_
     elif obj_type == 'release':
diff --git a/swh/model/tests/test_model.py b/swh/model/tests/test_model.py
index 220ba324798e9a5f522483f731502f16e9950793..f91868577235614cd5733957a0af6d19a289c046 100644
--- a/swh/model/tests/test_model.py
+++ b/swh/model/tests/test_model.py
@@ -7,6 +7,7 @@ import copy
 
 from hypothesis import given
 
+from swh.model.model import Content
 from swh.model.hypothesis_strategies import objects
 
 
@@ -24,3 +25,11 @@ def test_todict_inverse_fromdict(objtype_and_obj):
 
     # Check the composition of from_dict and to_dict is the identity
     assert obj_as_dict == type(obj).from_dict(obj_as_dict).to_dict()
+
+
+def test_content_get_hash():
+    hashes = dict(
+        sha1=b'foo', sha1_git=b'bar', sha256=b'baz', blake2s256=b'qux')
+    c = Content(length=42, status='visible', **hashes)
+    for (hash_name, hash_) in hashes.items():
+        assert c.get_hash(hash_name) == hash_
diff --git a/version.txt b/version.txt
index f57c086155d813c6da9d5222efe96821263bb513..d73351960bdbc86edfc8ef92e7024fa8f81763ad 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-v0.0.40-0-g56eb29f
\ No newline at end of file
+v0.0.41-0-g01a5d4c
\ No newline at end of file