Include TUF scripts in this repo.
authorIvan Alejandro <ivanalejandro0@gmail.com>
Fri, 24 Oct 2014 19:16:16 +0000 (16:16 -0300)
committerIvan Alejandro <ivanalejandro0@gmail.com>
Fri, 24 Oct 2014 19:16:16 +0000 (16:16 -0300)
Originally they were in the bitmask_client repo.

tuf-stuff.sh
tuf/init.py [new file with mode: 0755]
tuf/release.py [new file with mode: 0755]

index 8aa83ec..63c215f 100755 (executable)
@@ -109,7 +109,15 @@ do_init(){
     VENVDIR=$WORKDIR/tuf.venv
 
     BITMASK="Bitmask-linux$ARCH-$VERSION"
-    RELEASE=$BASE/../bitmask_client/pkg/tuf/release.py
+    RELEASE=$BASE/release.py
+
+    if [[ ! -f $RELEASE ]]; then
+        echo "ERROR: you need to copy the release.py file into this directory."
+    fi
+
+    if [[ ! -f $KEY_FILE ]]; then
+        echo "ERROR: the specified key file does not exist."
+    fi
 
     # Initialize path
     mkdir -p $WORKDIR
diff --git a/tuf/init.py b/tuf/init.py
new file mode 100755 (executable)
index 0000000..7300da0
--- /dev/null
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# init.py
+# Copyright (C) 2014 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Tool to initialize a TUF repo.
+
+The keys can be generated with:
+    openssl genrsa -des3 -out private.pem 4096
+The public key can be exported with:
+    openssl rsa -in private.pem -outform PEM -pubout -out public.pem
+"""
+
+import sys
+
+from tuf.repository_tool import create_new_repository
+from tuf.repository_tool import import_rsa_privatekey_from_file
+from tuf.repository_tool import import_rsa_publickey_from_file
+
+
+def usage():
+    print ("Usage:  %s repo root_private_key root_pub_key targets_pub_key"
+           " timestamp_pub_key") % (sys.argv[0],)
+
+
+def main():
+    if len(sys.argv) < 6:
+        usage()
+        return
+
+    repo_path = sys.argv[1]
+    root_priv_path = sys.argv[2]
+    root_pub_path = sys.argv[3]
+    targets_pub_path = sys.argv[4]
+    timestamp_pub_path = sys.argv[5]
+    repo = Repo(repo_path, root_priv_path)
+    repo.build(root_pub_path, targets_pub_path, timestamp_pub_path)
+
+    print "%s/metadata.staged/root.json is ready" % (repo_path,)
+
+
+class Repo(object):
+    """
+    Repository builder class
+    """
+
+    def __init__(self, repo_path, key_path):
+        """
+        Constructor
+
+        :param repo_path: path where the repo lives
+        :type repo_path: str
+        :param key_path: path where the private root key lives
+        :type key_path: str
+        """
+        self._repo_path = repo_path
+        self._key = import_rsa_privatekey_from_file(key_path)
+
+    def build(self, root_pub_path, targets_pub_path, timestamp_pub_path):
+        """
+        Create a new repo
+
+        :param root_pub_path: path where the public root key lives
+        :type root_pub_path: str
+        :param targets_pub_path: path where the public targets key lives
+        :type targets_pub_path: str
+        :param timestamp_pub_path: path where the public timestamp key lives
+        :type timestamp_pub_path: str
+        """
+        repository = create_new_repository(self._repo_path)
+
+        pub_root_key = import_rsa_publickey_from_file(root_pub_path)
+        repository.root.add_verification_key(pub_root_key)
+        repository.root.load_signing_key(self._key)
+
+        pub_target_key = import_rsa_publickey_from_file(targets_pub_path)
+        repository.targets.add_verification_key(pub_target_key)
+        repository.snapshot.add_verification_key(pub_target_key)
+        repository.targets.compressions = ["gz"]
+        repository.snapshot.compressions = ["gz"]
+
+        pub_timestamp_key = import_rsa_publickey_from_file(timestamp_pub_path)
+        repository.timestamp.add_verification_key(pub_timestamp_key)
+
+        repository.write_partial()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/tuf/release.py b/tuf/release.py
new file mode 100755 (executable)
index 0000000..0e1c989
--- /dev/null
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+# release.py
+# Copyright (C) 2014 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Tool to generate TUF related files after a release
+
+The 'repo' folder should contain two folders:
+  - 'metadata.staged' with all the jsons from the previows release
+  - 'targets' where the release targets are
+"""
+
+import datetime
+import os.path
+import sys
+
+from tuf.repository_tool import load_repository
+from tuf.repository_tool import import_rsa_privatekey_from_file
+
+"""
+Days until the expiration of targets.json and snapshot.json. After this ammount
+of days the TUF client won't accept this files.
+"""
+EXPIRATION_DAYS = 90
+
+
+def usage():
+    print "Usage:  %s repo key" % (sys.argv[0],)
+
+
+def main():
+    if len(sys.argv) < 3:
+        usage()
+        return
+
+    repo_path = sys.argv[1]
+    key_path = sys.argv[2]
+    targets = Targets(repo_path, key_path)
+    targets.build()
+
+    print "%s/metadata.staged/(targets|snapshot).json[.gz] are ready" % \
+          (repo_path,)
+
+
+class Targets(object):
+    """
+    Targets builder class
+    """
+
+    def __init__(self, repo_path, key_path):
+        """
+        Constructor
+
+        :param repo_path: path where the repo lives
+        :type repo_path: str
+        :param key_path: path where the private targets key lives
+        :type key_path: str
+        """
+        self._repo_path = repo_path
+        self._key = import_rsa_privatekey_from_file(key_path)
+
+    def build(self):
+        """
+        Generate snapshot.json[.gz] and targets.json[.gz]
+        """
+        self._repo = load_repository(self._repo_path)
+        self._load_targets()
+
+        self._repo.targets.load_signing_key(self._key)
+        self._repo.snapshot.load_signing_key(self._key)
+        self._repo.targets.compressions = ["gz"]
+        self._repo.snapshot.compressions = ["gz"]
+        self._repo.snapshot.expiration = (
+            datetime.datetime.now() +
+            datetime.timedelta(days=EXPIRATION_DAYS))
+        self._repo.targets.expiration = (
+            datetime.datetime.now() +
+            datetime.timedelta(days=EXPIRATION_DAYS))
+        self._repo.write_partial()
+
+    def _load_targets(self):
+        """
+        Load a list of targets
+        """
+        targets_path = os.path.join(self._repo_path, 'targets')
+        target_list = self._repo.get_filepaths_in_directory(
+            targets_path,
+            recursive_walk=True,
+            followlinks=True)
+
+        self._remove_obsolete_targets(target_list)
+
+        for target in target_list:
+            octal_file_permissions = oct(os.stat(target).st_mode)[3:]
+            custom_file_permissions = {
+                'file_permissions': octal_file_permissions
+            }
+            self._repo.targets.add_target(target, custom_file_permissions)
+
+    def _remove_obsolete_targets(self, target_list):
+        """
+        Remove obsolete targets from TUF targets
+
+        :param target_list: list of targets on full path comming from TUF
+                            get_filepaths_in_directory
+        :type target_list: list(str)
+        """
+        targets_path = os.path.join(self._repo_path, 'targets')
+        relative_path_list = map(lambda t: t.split("/targets")[1], target_list)
+        removed_targets = (set(self._repo.targets.target_files.keys())
+                           - set(relative_path_list))
+
+        for target in removed_targets:
+            target_rel_path = target
+            if target[0] == '/':
+                target_rel_path = target[1:]
+            target_path = os.path.join(targets_path, target_rel_path)
+            self._repo.targets.remove_target(target_path)
+
+
+if __name__ == "__main__":
+    main()