update root metadata via chaining
diff --git a/src/client.rs b/src/client.rs
index 2d79dbb..ea2c62b 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,10 +1,12 @@
 //! Clients for high level interactions with TUF repositories.
 
-use repository::Repository;
+use chrono::offset::Utc;
 
 use Result;
+use error::Error;
 use interchange::DataInterchange;
-use metadata::MetadataVersion;
+use metadata::{MetadataVersion, RootMetadata, Role};
+use repository::Repository;
 use tuf::Tuf;
 
 /// A client that interacts with TUF repositories.
@@ -37,28 +39,46 @@
         }
     }
 
-    /// Update TUF metadata from local and remote sources.
+    /// Update TUF metadata from local and remote repositories.
     pub fn update(&mut self) -> Result<()> {
         self.update_root()
     }
 
     fn update_root(&mut self) -> Result<()> {
-        // TODO this doesn't build the chain back up from scratch
-        let root = self.local.fetch_root(
-            &MetadataVersion::None,
-            &self.config.max_root_size,
-        )?;
-        self.tuf.update_root(root)?;
+        Self::update_root_chain(&mut self.tuf, &self.config.max_root_size, &mut self.local)?;
+        Self::update_root_chain(&mut self.tuf, &self.config.max_root_size, &mut self.remote)?;
 
-        // TODO this doesn't build the chain back up from scratch
-        let root = self.remote.fetch_root(
-            &MetadataVersion::None,
-            &self.config.max_root_size,
-        )?;
-        
-        // TODO store the newly fetched roots in the local repo
+        if self.tuf.root().expires() <= &Utc::now() {
+            Err(Error::ExpiredMetadata(Role::Root))
+        } else {
+            Ok(())
+        }
+    }
 
-        self.tuf.update_root(root)
+    fn update_root_chain<T>(tuf: &mut Tuf<D>, max_root_size: &Option<usize>, repo: &mut T) -> Result<()>
+    where
+        T: Repository<D>
+    {
+        let latest_root = repo.fetch_root(&MetadataVersion::None, max_root_size)?;
+        let latest_version = D::deserialize::<RootMetadata>(latest_root.unverified_signed())?
+            .version();
+
+        if latest_version < tuf.root().version() {
+            return Err(Error::VerificationFailure(format!(
+                "Latest root version is lower than current root version: {} < {}",
+                latest_version,
+                tuf.root().version()
+            )))
+        } else if latest_version == tuf.root().version() {
+            return Ok(())
+        }
+
+        for i in (tuf.root().version() + 1)..latest_version {
+            let signed = repo.fetch_root(&MetadataVersion::Number(i), max_root_size)?;
+            tuf.update_root(signed)?;
+        }
+
+        tuf.update_root(latest_root)
     }
 }
 
diff --git a/src/crypto.rs b/src/crypto.rs
index 3355919..620be47 100644
--- a/src/crypto.rs
+++ b/src/crypto.rs
@@ -226,7 +226,7 @@
 
     /// Create a `PublicKey` from an RSA `PublicKeyValue`, either SPKI or PKCS#1.
     pub fn from_rsa(value: PublicKeyValue, format: KeyFormat) -> Result<Self> {
-        // TODO check n > 2048 bits
+        // TODO check n > 2048 bits (but this is ok because `ring` doesn't support less)
 
         let key_id = calculate_key_id(&value);
 
diff --git a/src/error.rs b/src/error.rs
index 7007883..19c4d5a 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -7,6 +7,7 @@
 use std::io;
 use std::path::Path;
 
+use metadata::Role;
 use rsa::der;
 
 /// Error type for all TUF related errors.
@@ -18,6 +19,8 @@
     Decode(String),
     /// There was a problem encoding the metadata.
     Encode(String),
+    /// Metadata was expired.
+    ExpiredMetadata(Role),
     /// Generic catcher for all errors.
     Generic(String),
     /// An illegal argument was passed into a function.
diff --git a/src/metadata.rs b/src/metadata.rs
index b9552b8..770fd0d 100644
--- a/src/metadata.rs
+++ b/src/metadata.rs
@@ -99,7 +99,7 @@
     }
 
     /// An immutable reference to the unverified raw data.
-    /// 
+    ///
     /// *WARNING*: This data is untrusted.
     pub fn unverified_signed(&self) -> &D::RawData {
         &self.signed
diff --git a/src/tuf.rs b/src/tuf.rs
index 6713246..6bc4183 100644
--- a/src/tuf.rs
+++ b/src/tuf.rs
@@ -52,6 +52,11 @@
         })
     }
 
+    /// An immutable reference to the root metadata.
+    pub fn root(&self) -> &RootMetadata {
+        &self.root
+    }
+
     /// Verify and update the root metadata.
     pub fn update_root<V>(&mut self, signed_root: SignedMetadata<D, RootMetadata, V>) -> Result<()>
     where
@@ -67,17 +72,20 @@
 
         match root.version() {
             x if x == self.root.version() => {
-                info!("Attempted to update root to new metadata with the same version. Refusing to update.")
-            },
+                info!(
+                    "Attempted to update root to new metadata with the same version. Refusing to update."
+                )
+            }
             x if x < self.root.version() => {
-                return Err(Error::VerificationFailure(format!("Attempted to roll back root at version {} to {}.", self.root.version(), x)))
+                return Err(Error::VerificationFailure(format!(
+                    "Attempted to roll back root at version {} to {}.",
+                    self.root.version(),
+                    x
+                )))
             }
             _ => (),
         }
 
-        // TODO this is allowed to be expired, which is ok for updating the root chain, but not ok
-        // for actually verifying anything else later
-
         let _ = signed_root.verify(
             root.root().threshold(),
             root.root().key_ids(),