We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Pickle dump/load is used on handling the signature file


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nvflare/lighter/impl/signature.py`
Content:
```
1 # Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import os
16 import pickle
17 
18 from nvflare.lighter.spec import Builder, Study
19 from nvflare.lighter.utils import sign_all
20 
21 
22 class SignatureBuilder(Builder):
23     """Sign files with rootCA's private key.
24 
25     Creates signatures for all the files signed with the root CA for the startup kits so that they
26     can be cryptographically verified to ensure any tampering is detected. This builder writes the signature.pkl file.
27     """
28 
29     def build(self, study: Study, ctx: dict):
30         servers = study.get_participants_by_type("server", first_only=False)
31         for server in servers:
32             dest_dir = self.get_kit_dir(server, ctx)
33             root_pri_key = ctx.get("root_pri_key")
34             signatures = sign_all(dest_dir, root_pri_key)
35             pickle.dump(signatures, open(os.path.join(dest_dir, "signature.pkl"), "wb"))
36         for p in study.get_participants_by_type("client", first_only=False):
37             dest_dir = self.get_kit_dir(p, ctx)
38             root_pri_key = ctx.get("root_pri_key")
39             signatures = sign_all(dest_dir, root_pri_key)
40             pickle.dump(signatures, open(os.path.join(dest_dir, "signature.pkl"), "wb"))
41
```

Path: `nvflare/lighter/utils.py`
Content:
```
1 # Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import os
16 import random
17 
18 import yaml
19 from cryptography.hazmat.primitives import hashes
20 from cryptography.hazmat.primitives.asymmetric import padding
21 
22 
23 def generate_password():
24     s = "abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"
25     passlen = 16
26     p = "".join(random.sample(s, passlen))
27     return p
28 
29 
30 def sign_all(content_folder, signing_pri_key):
31     signatures = dict()
32     for f in os.listdir(content_folder):
33         path = os.path.join(content_folder, f)
34         if os.path.isfile(path):
35             signature = signing_pri_key.sign(
36                 data=open(path, "rb").read(),
37                 padding=padding.PSS(
38                     mgf=padding.MGF1(hashes.SHA256()),
39                     salt_length=padding.PSS.MAX_LENGTH,
40                 ),
41                 algorithm=hashes.SHA256(),
42             )
43             signatures[f] = signature
44     return signatures
45 
46 
47 def load_yaml(file_name):
48     return yaml.load(open(file_name, "r"), Loader=yaml.Loader)
49 
50 
51 def sh_replace(src, mapping_dict):
52     result = src
53     for k, v in mapping_dict.items():
54         result = result.replace("{~~" + k + "~~}", str(v))
55     return result
56
```

Path: `nvflare/fuel/sec/security_content_service.py`
Content:
```
1 # Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import json
16 import os
17 import pickle
18 from enum import Enum
19 
20 from cryptography import x509
21 from cryptography.exceptions import InvalidSignature
22 from cryptography.hazmat.backends import default_backend
23 from cryptography.hazmat.primitives import hashes
24 from cryptography.hazmat.primitives.asymmetric import padding
25 
26 
27 class LoadResult(Enum):
28     """Constants for different results when loading secure content."""
29 
30     OK = "ok"
31     NOT_MANAGED = "notManaged"
32     NO_SUCH_CONTENT = "noSuchContent"
33     NOT_SIGNED = "notSigned"
34     INVALID_SIGNATURE = "invalidSignature"
35     INVALID_CONTENT = "invalidContent"
36 
37 
38 class SecurityContentManager(object):
39     def __init__(self, content_folder, signature_filename="signature.pkl", root_cert="rootCA.pem"):
40         """Content manager used by SecurityContentService to load secure content.
41 
42         Args:
43             content_folder (str): the folder path that includes signature file
44             signature_filename (str, optional): the signature file (pickled dictionary). Defaults to "signature.pkl".
45             root_cert (str, optional): root CA certificate filename. Defaults to "rootCA.pem".
46         """
47         self.content_folder = content_folder
48         signature_path = os.path.join(self.content_folder, signature_filename)
49         rootCA_cert_path = os.path.join(self.content_folder, root_cert)
50         if os.path.exists(signature_path) and os.path.exists(rootCA_cert_path):
51             self.signature = pickle.load(open(signature_path, "rb"))
52             cert = x509.load_pem_x509_certificate(open(rootCA_cert_path, "rb").read(), default_backend())
53             self.public_key = cert.public_key()
54             self.valid_config = True
55         else:
56             self.signature = dict()
57             self.valid_config = False
58 
59     def load_content(self, file_under_verification):
60         """Loads the data of the file under verification and verifies that the signature is valid.
61 
62         Args:
63             file_under_verification: file to load and verify
64 
65         Returns: Tuple of the file data and the LoadResult. File data may be None if the data cannot be loaded.
66 
67         """
68         full_path = os.path.join(self.content_folder, file_under_verification)
69         data = None
70         if not os.path.exists(full_path):
71             return data, LoadResult.NO_SUCH_CONTENT
72 
73         with open(full_path, "rb") as f:
74             data = f.read()
75         if not data:
76             return data, LoadResult.NO_SUCH_CONTENT
77 
78         if self.valid_config and file_under_verification in self.signature:
79             signature = self.signature[file_under_verification]
80             try:
81                 self.public_key.verify(
82                     signature=signature,
83                     data=data,
84                     padding=padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),
85                     algorithm=hashes.SHA256(),
86                 )
87                 result = LoadResult.OK
88             except InvalidSignature:
89                 result = LoadResult.INVALID_SIGNATURE
90         else:
91             result = LoadResult.NOT_SIGNED
92         return data, result
93 
94 
95 class SecurityContentService(object):
96     """Uses SecurityContentManager to load secure content."""
97 
98     security_content_manager = None
99 
100     @staticmethod
101     def initialize(content_folder: str, signature_filename="signature.pkl", root_cert="rootCA.pem"):
102         if SecurityContentService.security_content_manager is None:
103             SecurityContentService.security_content_manager = SecurityContentManager(
104                 content_folder, signature_filename, root_cert
105             )
106 
107     @staticmethod
108     def load_content(file_under_verification):
109         if not SecurityContentService.security_content_manager:
110             return None, LoadResult.NOT_MANAGED
111 
112         return SecurityContentService.security_content_manager.load_content(file_under_verification)
113 
114     @staticmethod
115     def load_json(file_under_verification):
116         json_data = None
117 
118         data_bytes, result = SecurityContentService.security_content_manager.load_content(file_under_verification)
119 
120         if data_bytes:
121             try:
122                 data_text = data_bytes.decode("ascii")
123                 json_data = json.loads(data_text)
124             except json.JSONDecodeError:
125                 return None, LoadResult.INVALID_CONTENT
126 
127         return json_data, result
128
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/nvflare/fuel/sec/security_content_service.py b/nvflare/fuel/sec/security_content_service.py
--- a/nvflare/fuel/sec/security_content_service.py
+++ b/nvflare/fuel/sec/security_content_service.py
@@ -14,7 +14,7 @@
 
 import json
 import os
-import pickle
+from base64 import b64decode
 from enum import Enum
 
 from cryptography import x509
@@ -36,19 +36,21 @@
 
 
 class SecurityContentManager(object):
-    def __init__(self, content_folder, signature_filename="signature.pkl", root_cert="rootCA.pem"):
+    def __init__(self, content_folder, signature_filename="signature.json", root_cert="rootCA.pem"):
         """Content manager used by SecurityContentService to load secure content.
 
         Args:
             content_folder (str): the folder path that includes signature file
-            signature_filename (str, optional): the signature file (pickled dictionary). Defaults to "signature.pkl".
+            signature_filename (str, optional): the signature file (signed dictionary). Defaults to "signature.json".
             root_cert (str, optional): root CA certificate filename. Defaults to "rootCA.pem".
         """
         self.content_folder = content_folder
         signature_path = os.path.join(self.content_folder, signature_filename)
         rootCA_cert_path = os.path.join(self.content_folder, root_cert)
         if os.path.exists(signature_path) and os.path.exists(rootCA_cert_path):
-            self.signature = pickle.load(open(signature_path, "rb"))
+            self.signature = json.load(open(signature_path, "rt"))
+            for k in self.signature:
+                self.signature[k] = b64decode(self.signature[k].encode("utf-8"))
             cert = x509.load_pem_x509_certificate(open(rootCA_cert_path, "rb").read(), default_backend())
             self.public_key = cert.public_key()
             self.valid_config = True
@@ -98,7 +100,7 @@
     security_content_manager = None
 
     @staticmethod
-    def initialize(content_folder: str, signature_filename="signature.pkl", root_cert="rootCA.pem"):
+    def initialize(content_folder: str, signature_filename="signature.json", root_cert="rootCA.pem"):
         if SecurityContentService.security_content_manager is None:
             SecurityContentService.security_content_manager = SecurityContentManager(
                 content_folder, signature_filename, root_cert
diff --git a/nvflare/lighter/impl/signature.py b/nvflare/lighter/impl/signature.py
--- a/nvflare/lighter/impl/signature.py
+++ b/nvflare/lighter/impl/signature.py
@@ -12,8 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import json
 import os
-import pickle
 
 from nvflare.lighter.spec import Builder, Study
 from nvflare.lighter.utils import sign_all
@@ -32,9 +32,9 @@
             dest_dir = self.get_kit_dir(server, ctx)
             root_pri_key = ctx.get("root_pri_key")
             signatures = sign_all(dest_dir, root_pri_key)
-            pickle.dump(signatures, open(os.path.join(dest_dir, "signature.pkl"), "wb"))
+            json.dump(signatures, open(os.path.join(dest_dir, "signature.json"), "wt"))
         for p in study.get_participants_by_type("client", first_only=False):
             dest_dir = self.get_kit_dir(p, ctx)
             root_pri_key = ctx.get("root_pri_key")
             signatures = sign_all(dest_dir, root_pri_key)
-            pickle.dump(signatures, open(os.path.join(dest_dir, "signature.pkl"), "wb"))
+            json.dump(signatures, open(os.path.join(dest_dir, "signature.json"), "wt"))
diff --git a/nvflare/lighter/utils.py b/nvflare/lighter/utils.py
--- a/nvflare/lighter/utils.py
+++ b/nvflare/lighter/utils.py
@@ -14,6 +14,7 @@
 
 import os
 import random
+from base64 import b64encode
 
 import yaml
 from cryptography.hazmat.primitives import hashes
@@ -40,7 +41,7 @@
                 ),
                 algorithm=hashes.SHA256(),
             )
-            signatures[f] = signature
+            signatures[f] = b64encode(signature).decode("utf-8")
     return signatures

{"golden_diff": "diff --git a/nvflare/fuel/sec/security_content_service.py b/nvflare/fuel/sec/security_content_service.py\n--- a/nvflare/fuel/sec/security_content_service.py\n+++ b/nvflare/fuel/sec/security_content_service.py\n@@ -14,7 +14,7 @@\n \n import json\n import os\n-import pickle\n+from base64 import b64decode\n from enum import Enum\n \n from cryptography import x509\n@@ -36,19 +36,21 @@\n \n \n class SecurityContentManager(object):\n-    def __init__(self, content_folder, signature_filename=\"signature.pkl\", root_cert=\"rootCA.pem\"):\n+    def __init__(self, content_folder, signature_filename=\"signature.json\", root_cert=\"rootCA.pem\"):\n         \"\"\"Content manager used by SecurityContentService to load secure content.\n \n         Args:\n             content_folder (str): the folder path that includes signature file\n-            signature_filename (str, optional): the signature file (pickled dictionary). Defaults to \"signature.pkl\".\n+            signature_filename (str, optional): the signature file (signed dictionary). Defaults to \"signature.json\".\n             root_cert (str, optional): root CA certificate filename. Defaults to \"rootCA.pem\".\n         \"\"\"\n         self.content_folder = content_folder\n         signature_path = os.path.join(self.content_folder, signature_filename)\n         rootCA_cert_path = os.path.join(self.content_folder, root_cert)\n         if os.path.exists(signature_path) and os.path.exists(rootCA_cert_path):\n-            self.signature = pickle.load(open(signature_path, \"rb\"))\n+            self.signature = json.load(open(signature_path, \"rt\"))\n+            for k in self.signature:\n+                self.signature[k] = b64decode(self.signature[k].encode(\"utf-8\"))\n             cert = x509.load_pem_x509_certificate(open(rootCA_cert_path, \"rb\").read(), default_backend())\n             self.public_key = cert.public_key()\n             self.valid_config = True\n@@ -98,7 +100,7 @@\n     security_content_manager = None\n \n     @staticmethod\n-    def initialize(content_folder: str, signature_filename=\"signature.pkl\", root_cert=\"rootCA.pem\"):\n+    def initialize(content_folder: str, signature_filename=\"signature.json\", root_cert=\"rootCA.pem\"):\n         if SecurityContentService.security_content_manager is None:\n             SecurityContentService.security_content_manager = SecurityContentManager(\n                 content_folder, signature_filename, root_cert\ndiff --git a/nvflare/lighter/impl/signature.py b/nvflare/lighter/impl/signature.py\n--- a/nvflare/lighter/impl/signature.py\n+++ b/nvflare/lighter/impl/signature.py\n@@ -12,8 +12,8 @@\n # See the License for the specific language governing permissions and\n # limitations under the License.\n \n+import json\n import os\n-import pickle\n \n from nvflare.lighter.spec import Builder, Study\n from nvflare.lighter.utils import sign_all\n@@ -32,9 +32,9 @@\n             dest_dir = self.get_kit_dir(server, ctx)\n             root_pri_key = ctx.get(\"root_pri_key\")\n             signatures = sign_all(dest_dir, root_pri_key)\n-            pickle.dump(signatures, open(os.path.join(dest_dir, \"signature.pkl\"), \"wb\"))\n+            json.dump(signatures, open(os.path.join(dest_dir, \"signature.json\"), \"wt\"))\n         for p in study.get_participants_by_type(\"client\", first_only=False):\n             dest_dir = self.get_kit_dir(p, ctx)\n             root_pri_key = ctx.get(\"root_pri_key\")\n             signatures = sign_all(dest_dir, root_pri_key)\n-            pickle.dump(signatures, open(os.path.join(dest_dir, \"signature.pkl\"), \"wb\"))\n+            json.dump(signatures, open(os.path.join(dest_dir, \"signature.json\"), \"wt\"))\ndiff --git a/nvflare/lighter/utils.py b/nvflare/lighter/utils.py\n--- a/nvflare/lighter/utils.py\n+++ b/nvflare/lighter/utils.py\n@@ -14,6 +14,7 @@\n \n import os\n import random\n+from base64 import b64encode\n \n import yaml\n from cryptography.hazmat.primitives import hashes\n@@ -40,7 +41,7 @@\n                 ),\n                 algorithm=hashes.SHA256(),\n             )\n-            signatures[f] = signature\n+            signatures[f] = b64encode(signature).decode(\"utf-8\")\n     return signatures\n", "issue": "Pickle dump/load is used on handling the signature file\n\n", "before_files": [{"content": "# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport pickle\n\nfrom nvflare.lighter.spec import Builder, Study\nfrom nvflare.lighter.utils import sign_all\n\n\nclass SignatureBuilder(Builder):\n    \"\"\"Sign files with rootCA's private key.\n\n    Creates signatures for all the files signed with the root CA for the startup kits so that they\n    can be cryptographically verified to ensure any tampering is detected. This builder writes the signature.pkl file.\n    \"\"\"\n\n    def build(self, study: Study, ctx: dict):\n        servers = study.get_participants_by_type(\"server\", first_only=False)\n        for server in servers:\n            dest_dir = self.get_kit_dir(server, ctx)\n            root_pri_key = ctx.get(\"root_pri_key\")\n            signatures = sign_all(dest_dir, root_pri_key)\n            pickle.dump(signatures, open(os.path.join(dest_dir, \"signature.pkl\"), \"wb\"))\n        for p in study.get_participants_by_type(\"client\", first_only=False):\n            dest_dir = self.get_kit_dir(p, ctx)\n            root_pri_key = ctx.get(\"root_pri_key\")\n            signatures = sign_all(dest_dir, root_pri_key)\n            pickle.dump(signatures, open(os.path.join(dest_dir, \"signature.pkl\"), \"wb\"))\n", "path": "nvflare/lighter/impl/signature.py"}, {"content": "# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport random\n\nimport yaml\nfrom cryptography.hazmat.primitives import hashes\nfrom cryptography.hazmat.primitives.asymmetric import padding\n\n\ndef generate_password():\n    s = \"abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n    passlen = 16\n    p = \"\".join(random.sample(s, passlen))\n    return p\n\n\ndef sign_all(content_folder, signing_pri_key):\n    signatures = dict()\n    for f in os.listdir(content_folder):\n        path = os.path.join(content_folder, f)\n        if os.path.isfile(path):\n            signature = signing_pri_key.sign(\n                data=open(path, \"rb\").read(),\n                padding=padding.PSS(\n                    mgf=padding.MGF1(hashes.SHA256()),\n                    salt_length=padding.PSS.MAX_LENGTH,\n                ),\n                algorithm=hashes.SHA256(),\n            )\n            signatures[f] = signature\n    return signatures\n\n\ndef load_yaml(file_name):\n    return yaml.load(open(file_name, \"r\"), Loader=yaml.Loader)\n\n\ndef sh_replace(src, mapping_dict):\n    result = src\n    for k, v in mapping_dict.items():\n        result = result.replace(\"{~~\" + k + \"~~}\", str(v))\n    return result\n", "path": "nvflare/lighter/utils.py"}, {"content": "# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport json\nimport os\nimport pickle\nfrom enum import Enum\n\nfrom cryptography import x509\nfrom cryptography.exceptions import InvalidSignature\nfrom cryptography.hazmat.backends import default_backend\nfrom cryptography.hazmat.primitives import hashes\nfrom cryptography.hazmat.primitives.asymmetric import padding\n\n\nclass LoadResult(Enum):\n    \"\"\"Constants for different results when loading secure content.\"\"\"\n\n    OK = \"ok\"\n    NOT_MANAGED = \"notManaged\"\n    NO_SUCH_CONTENT = \"noSuchContent\"\n    NOT_SIGNED = \"notSigned\"\n    INVALID_SIGNATURE = \"invalidSignature\"\n    INVALID_CONTENT = \"invalidContent\"\n\n\nclass SecurityContentManager(object):\n    def __init__(self, content_folder, signature_filename=\"signature.pkl\", root_cert=\"rootCA.pem\"):\n        \"\"\"Content manager used by SecurityContentService to load secure content.\n\n        Args:\n            content_folder (str): the folder path that includes signature file\n            signature_filename (str, optional): the signature file (pickled dictionary). Defaults to \"signature.pkl\".\n            root_cert (str, optional): root CA certificate filename. Defaults to \"rootCA.pem\".\n        \"\"\"\n        self.content_folder = content_folder\n        signature_path = os.path.join(self.content_folder, signature_filename)\n        rootCA_cert_path = os.path.join(self.content_folder, root_cert)\n        if os.path.exists(signature_path) and os.path.exists(rootCA_cert_path):\n            self.signature = pickle.load(open(signature_path, \"rb\"))\n            cert = x509.load_pem_x509_certificate(open(rootCA_cert_path, \"rb\").read(), default_backend())\n            self.public_key = cert.public_key()\n            self.valid_config = True\n        else:\n            self.signature = dict()\n            self.valid_config = False\n\n    def load_content(self, file_under_verification):\n        \"\"\"Loads the data of the file under verification and verifies that the signature is valid.\n\n        Args:\n            file_under_verification: file to load and verify\n\n        Returns: Tuple of the file data and the LoadResult. File data may be None if the data cannot be loaded.\n\n        \"\"\"\n        full_path = os.path.join(self.content_folder, file_under_verification)\n        data = None\n        if not os.path.exists(full_path):\n            return data, LoadResult.NO_SUCH_CONTENT\n\n        with open(full_path, \"rb\") as f:\n            data = f.read()\n        if not data:\n            return data, LoadResult.NO_SUCH_CONTENT\n\n        if self.valid_config and file_under_verification in self.signature:\n            signature = self.signature[file_under_verification]\n            try:\n                self.public_key.verify(\n                    signature=signature,\n                    data=data,\n                    padding=padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),\n                    algorithm=hashes.SHA256(),\n                )\n                result = LoadResult.OK\n            except InvalidSignature:\n                result = LoadResult.INVALID_SIGNATURE\n        else:\n            result = LoadResult.NOT_SIGNED\n        return data, result\n\n\nclass SecurityContentService(object):\n    \"\"\"Uses SecurityContentManager to load secure content.\"\"\"\n\n    security_content_manager = None\n\n    @staticmethod\n    def initialize(content_folder: str, signature_filename=\"signature.pkl\", root_cert=\"rootCA.pem\"):\n        if SecurityContentService.security_content_manager is None:\n            SecurityContentService.security_content_manager = SecurityContentManager(\n                content_folder, signature_filename, root_cert\n            )\n\n    @staticmethod\n    def load_content(file_under_verification):\n        if not SecurityContentService.security_content_manager:\n            return None, LoadResult.NOT_MANAGED\n\n        return SecurityContentService.security_content_manager.load_content(file_under_verification)\n\n    @staticmethod\n    def load_json(file_under_verification):\n        json_data = None\n\n        data_bytes, result = SecurityContentService.security_content_manager.load_content(file_under_verification)\n\n        if data_bytes:\n            try:\n                data_text = data_bytes.decode(\"ascii\")\n                json_data = json.loads(data_text)\n            except json.JSONDecodeError:\n                return None, LoadResult.INVALID_CONTENT\n\n        return json_data, result\n", "path": "nvflare/fuel/sec/security_content_service.py"}], "after_files": [{"content": "# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport json\nimport os\n\nfrom nvflare.lighter.spec import Builder, Study\nfrom nvflare.lighter.utils import sign_all\n\n\nclass SignatureBuilder(Builder):\n    \"\"\"Sign files with rootCA's private key.\n\n    Creates signatures for all the files signed with the root CA for the startup kits so that they\n    can be cryptographically verified to ensure any tampering is detected. This builder writes the signature.pkl file.\n    \"\"\"\n\n    def build(self, study: Study, ctx: dict):\n        servers = study.get_participants_by_type(\"server\", first_only=False)\n        for server in servers:\n            dest_dir = self.get_kit_dir(server, ctx)\n            root_pri_key = ctx.get(\"root_pri_key\")\n            signatures = sign_all(dest_dir, root_pri_key)\n            json.dump(signatures, open(os.path.join(dest_dir, \"signature.json\"), \"wt\"))\n        for p in study.get_participants_by_type(\"client\", first_only=False):\n            dest_dir = self.get_kit_dir(p, ctx)\n            root_pri_key = ctx.get(\"root_pri_key\")\n            signatures = sign_all(dest_dir, root_pri_key)\n            json.dump(signatures, open(os.path.join(dest_dir, \"signature.json\"), \"wt\"))\n", "path": "nvflare/lighter/impl/signature.py"}, {"content": "# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport random\nfrom base64 import b64encode\n\nimport yaml\nfrom cryptography.hazmat.primitives import hashes\nfrom cryptography.hazmat.primitives.asymmetric import padding\n\n\ndef generate_password():\n    s = \"abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n    passlen = 16\n    p = \"\".join(random.sample(s, passlen))\n    return p\n\n\ndef sign_all(content_folder, signing_pri_key):\n    signatures = dict()\n    for f in os.listdir(content_folder):\n        path = os.path.join(content_folder, f)\n        if os.path.isfile(path):\n            signature = signing_pri_key.sign(\n                data=open(path, \"rb\").read(),\n                padding=padding.PSS(\n                    mgf=padding.MGF1(hashes.SHA256()),\n                    salt_length=padding.PSS.MAX_LENGTH,\n                ),\n                algorithm=hashes.SHA256(),\n            )\n            signatures[f] = b64encode(signature).decode(\"utf-8\")\n    return signatures\n\n\ndef load_yaml(file_name):\n    return yaml.load(open(file_name, \"r\"), Loader=yaml.Loader)\n\n\ndef sh_replace(src, mapping_dict):\n    result = src\n    for k, v in mapping_dict.items():\n        result = result.replace(\"{~~\" + k + \"~~}\", str(v))\n    return result\n", "path": "nvflare/lighter/utils.py"}, {"content": "# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport json\nimport os\nfrom base64 import b64decode\nfrom enum import Enum\n\nfrom cryptography import x509\nfrom cryptography.exceptions import InvalidSignature\nfrom cryptography.hazmat.backends import default_backend\nfrom cryptography.hazmat.primitives import hashes\nfrom cryptography.hazmat.primitives.asymmetric import padding\n\n\nclass LoadResult(Enum):\n    \"\"\"Constants for different results when loading secure content.\"\"\"\n\n    OK = \"ok\"\n    NOT_MANAGED = \"notManaged\"\n    NO_SUCH_CONTENT = \"noSuchContent\"\n    NOT_SIGNED = \"notSigned\"\n    INVALID_SIGNATURE = \"invalidSignature\"\n    INVALID_CONTENT = \"invalidContent\"\n\n\nclass SecurityContentManager(object):\n    def __init__(self, content_folder, signature_filename=\"signature.json\", root_cert=\"rootCA.pem\"):\n        \"\"\"Content manager used by SecurityContentService to load secure content.\n\n        Args:\n            content_folder (str): the folder path that includes signature file\n            signature_filename (str, optional): the signature file (signed dictionary). Defaults to \"signature.json\".\n            root_cert (str, optional): root CA certificate filename. Defaults to \"rootCA.pem\".\n        \"\"\"\n        self.content_folder = content_folder\n        signature_path = os.path.join(self.content_folder, signature_filename)\n        rootCA_cert_path = os.path.join(self.content_folder, root_cert)\n        if os.path.exists(signature_path) and os.path.exists(rootCA_cert_path):\n            self.signature = json.load(open(signature_path, \"rt\"))\n            for k in self.signature:\n                self.signature[k] = b64decode(self.signature[k].encode(\"utf-8\"))\n            cert = x509.load_pem_x509_certificate(open(rootCA_cert_path, \"rb\").read(), default_backend())\n            self.public_key = cert.public_key()\n            self.valid_config = True\n        else:\n            self.signature = dict()\n            self.valid_config = False\n\n    def load_content(self, file_under_verification):\n        \"\"\"Loads the data of the file under verification and verifies that the signature is valid.\n\n        Args:\n            file_under_verification: file to load and verify\n\n        Returns: Tuple of the file data and the LoadResult. File data may be None if the data cannot be loaded.\n\n        \"\"\"\n        full_path = os.path.join(self.content_folder, file_under_verification)\n        data = None\n        if not os.path.exists(full_path):\n            return data, LoadResult.NO_SUCH_CONTENT\n\n        with open(full_path, \"rb\") as f:\n            data = f.read()\n        if not data:\n            return data, LoadResult.NO_SUCH_CONTENT\n\n        if self.valid_config and file_under_verification in self.signature:\n            signature = self.signature[file_under_verification]\n            try:\n                self.public_key.verify(\n                    signature=signature,\n                    data=data,\n                    padding=padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),\n                    algorithm=hashes.SHA256(),\n                )\n                result = LoadResult.OK\n            except InvalidSignature:\n                result = LoadResult.INVALID_SIGNATURE\n        else:\n            result = LoadResult.NOT_SIGNED\n        return data, result\n\n\nclass SecurityContentService(object):\n    \"\"\"Uses SecurityContentManager to load secure content.\"\"\"\n\n    security_content_manager = None\n\n    @staticmethod\n    def initialize(content_folder: str, signature_filename=\"signature.json\", root_cert=\"rootCA.pem\"):\n        if SecurityContentService.security_content_manager is None:\n            SecurityContentService.security_content_manager = SecurityContentManager(\n                content_folder, signature_filename, root_cert\n            )\n\n    @staticmethod\n    def load_content(file_under_verification):\n        if not SecurityContentService.security_content_manager:\n            return None, LoadResult.NOT_MANAGED\n\n        return SecurityContentService.security_content_manager.load_content(file_under_verification)\n\n    @staticmethod\n    def load_json(file_under_verification):\n        json_data = None\n\n        data_bytes, result = SecurityContentService.security_content_manager.load_content(file_under_verification)\n\n        if data_bytes:\n            try:\n                data_text = data_bytes.decode(\"ascii\")\n                json_data = json.loads(data_text)\n            except json.JSONDecodeError:\n                return None, LoadResult.INVALID_CONTENT\n\n        return json_data, result\n", "path": "nvflare/fuel/sec/security_content_service.py"}]}