Acloud over secure webrtc openssl command implementation.
Use openssl tool instead of mkcert.
Bug: 214337220
Test: acloud-dev create
acloud-dev create --local-image
acloud-dev create --local-instance
acloud-dev create --local-instance --local-image
acloud-dev setup
Change-Id: I01ea06b2ee30b69683f645c4b0b1b2f0d365d9cd
diff --git a/setup/mkcert.py b/setup/mkcert.py
new file mode 100644
index 0000000..49a8fe3
--- /dev/null
+++ b/setup/mkcert.py
@@ -0,0 +1,162 @@
+# Copyright 2022 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+r"""Mkcert entry point.
+
+Mkcert will handle the SSL certificates process to secure WEB browser of
+a local or remote instance of an Android Virtual Device.
+"""
+
+import filecmp
+import logging
+import os
+import platform
+
+from acloud.internal import constants
+from acloud.internal.lib import utils
+
+logger = logging.getLogger(__name__)
+
+_CA_NAME = constants.SSL_CA_NAME
+_CERT_DIR = os.path.join(os.path.expanduser("~"), constants.SSL_DIR)
+_CA_KEY_PATH = os.path.join(_CERT_DIR, f"{_CA_NAME}.key")
+_CA_CRT_PATH = os.path.join(_CERT_DIR, f"{_CA_NAME}.pem")
+_CERT_KEY_PATH = os.path.join(_CERT_DIR, "server.key")
+_CERT_CSR_PATH = os.path.join(_CERT_DIR, "server.csr")
+_CERT_CRT_PATH = os.path.join(_CERT_DIR, "server.crt")
+_CA_EXT = "keyUsage=critical,keyCertSign"
+_CA_SUBJ="/OU=acloud/O=acloud development CA/CN=localhost"
+_CERT_SUBJ = "/OU=%s/O=acloud development CA" % platform.node()
+_TRUST_CA_PATH = os.path.join(constants.SSL_TRUST_CA_DIR,
+ f"{_CA_NAME}.crt")
+_CERT_CRT_EXT = ";".join(f"echo \"{ext}\"" for ext in [
+ "keyUsage = critical, digitalSignature, keyEncipherment",
+ "extendedKeyUsage = serverAuth",
+ "subjectAltName = DNS.1:localhost, IP.1:0.0.0.0, IP.2:::1"])
+
+# Generate a Root SSL Certificate.
+_CA_CMD = (f"openssl req -new -x509 -days 9999 -newkey rsa:2048 "
+ f"-sha256 -nodes -keyout \"{_CA_KEY_PATH}\" "
+ f"-out \"{_CA_CRT_PATH}\" -extensions v3_ca "
+ f"-subj \"{_CA_SUBJ}\" -addext \"{_CA_EXT}\"")
+
+# Trust the Root SSL Certificate.
+_TRUST_CA_COPY_CMD = f"sudo cp {_CA_CRT_PATH} {_TRUST_CA_PATH}"
+_UPDATE_TRUST_CA_CMD = "sudo update-ca-certificates"
+_TRUST_CHROME_CMD = (
+ "certutil -d sql:$HOME/.pki/nssdb -A -t TC "
+ f"-n \"{_CA_NAME}\" -i \"{_TRUST_CA_PATH}\"")
+
+# Generate an SSL SAN Certificate with the Root Certificate.
+_CERT_KEY_CMD = f"openssl genrsa -out \"{_CERT_KEY_PATH}\" 2048"
+_CERT_CSR_CMD = (f"openssl req -new -key \"{_CERT_KEY_PATH}\" "
+ f"-out \"{_CERT_CSR_PATH}\" -subj \"{_CERT_SUBJ}\"")
+_CERT_CRT_CMD = (
+ f"openssl x509 -req -days 9999 -in \"{_CERT_CSR_PATH}\" "
+ f"-CA \"{_CA_CRT_PATH}\" -CAkey \"{_CA_KEY_PATH}\" "
+ f"-CAcreateserial -out \"{_CERT_CRT_PATH}\" "
+ f"-extfile <({_CERT_CRT_EXT};)")
+
+# UnInstall the Root SSL Certificate.
+_UNDO_TRUST_CA_CMD = f"sudo rm {_TRUST_CA_PATH}"
+_UNDO_TRUST_CHROME_CMD = f"certutil -D -d sql:$HOME/.pki/nssdb -n \"{_CA_NAME}\""
+
+
+def Install():
+ """Install Root SSL Certificates by the openssl tool.
+
+ Generates a Root SSL Certificates and setup the host environment
+ to build a secure browser for WebRTC AVD.
+
+ Returns:
+ True when the Root SSL Certificates are generated and setup.
+ """
+ if not os.path.isdir(_CERT_DIR):
+ os.mkdir(_CERT_DIR)
+
+ if os.path.exists(_TRUST_CA_PATH):
+ UnInstall()
+
+ if not os.path.exists(_CA_KEY_PATH) or not os.path.exists(_CA_CRT_PATH):
+ utils.Popen(_CA_CMD, shell=True)
+ if not os.path.exists(_TRUST_CA_PATH):
+ utils.Popen(_TRUST_CA_COPY_CMD, shell=True)
+ utils.Popen(_UPDATE_TRUST_CA_CMD, shell=True)
+ utils.Popen(_TRUST_CHROME_CMD, shell=True)
+
+ return IsRootCAReady()
+
+
+def AllocateLocalHostCert():
+ """Allocate localhost certificate by the openssl tool.
+
+ Generate an SSL SAN Certificate with the Root Certificate.
+
+ Returns:
+ True if the certificates is exist.
+ """
+ if not IsRootCAReady():
+ logger.debug("Can't load CA files.")
+ return False
+
+ if not os.path.exists(_CERT_KEY_PATH):
+ utils.Popen(_CERT_KEY_CMD, shell=True)
+ if not os.path.exists(_CERT_CSR_PATH):
+ utils.Popen(_CERT_CSR_CMD, shell=True)
+ if not os.path.exists(_CERT_CRT_PATH):
+ utils.Popen(_CERT_CRT_CMD, shell=True)
+
+ return IsCertificateReady()
+
+
+def IsRootCAReady():
+ """Check if the Root SSL Certificates are all ready.
+
+ Returns:
+ True if the Root SSL Certificates are exist.
+ """
+ for cert_file_name in [_CA_KEY_PATH, _CA_CRT_PATH, _TRUST_CA_PATH]:
+ if not os.path.exists(cert_file_name):
+ logger.debug("Root SSL Certificate: %s, does not exist",
+ cert_file_name)
+ return False
+
+ if not filecmp.cmp(_CA_CRT_PATH, _TRUST_CA_PATH):
+ logger.debug("The trusted CA %s file is not the same with %s ",
+ _TRUST_CA_PATH, _CA_CRT_PATH)
+ return False
+ return True
+
+
+def IsCertificateReady():
+ """Check if the SSL SAN Certificates files are all ready.
+
+ Returns:
+ True if the SSL SAN Certificates files existed.
+ """
+ for cert_file_name in [_CERT_KEY_PATH, _CERT_CRT_PATH]:
+ if not os.path.exists(cert_file_name):
+ logger.debug("SSL SAN Certificate: %s, does not exist",
+ cert_file_name)
+ return False
+ return True
+
+
+def UnInstall():
+ """Uninstall a Root SSL Certificate.
+
+ Undo the Root SSL Certificate host setup.
+ """
+ utils.Popen(_UNDO_TRUST_CA_CMD, shell=True)
+ utils.Popen(_UPDATE_TRUST_CA_CMD, shell=True)
+ utils.Popen(_UNDO_TRUST_CHROME_CMD, shell=True)