blob: 42636b4cb70f86f09ac0f2d5f591db2eee148fe9 [file] [log] [blame]
chojoyceb0817032022-01-12 18:29:36 +08001# Copyright 2022 - The Android Open Source Project
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.
14r"""Mkcert entry point.
15
16Mkcert will handle the SSL certificates process to secure WEB browser of
17a local or remote instance of an Android Virtual Device.
18"""
19
20import filecmp
21import logging
22import os
23import platform
chojoyce32ee70e2022-02-11 12:39:53 +080024import shutil
chojoyceb0817032022-01-12 18:29:36 +080025
26from acloud.internal import constants
27from acloud.internal.lib import utils
28
29logger = logging.getLogger(__name__)
30
31_CA_NAME = constants.SSL_CA_NAME
32_CERT_DIR = os.path.join(os.path.expanduser("~"), constants.SSL_DIR)
33_CA_KEY_PATH = os.path.join(_CERT_DIR, f"{_CA_NAME}.key")
34_CA_CRT_PATH = os.path.join(_CERT_DIR, f"{_CA_NAME}.pem")
35_CERT_KEY_PATH = os.path.join(_CERT_DIR, "server.key")
36_CERT_CSR_PATH = os.path.join(_CERT_DIR, "server.csr")
37_CERT_CRT_PATH = os.path.join(_CERT_DIR, "server.crt")
38_CA_EXT = "keyUsage=critical,keyCertSign"
39_CA_SUBJ="/OU=acloud/O=acloud development CA/CN=localhost"
40_CERT_SUBJ = "/OU=%s/O=acloud development CA" % platform.node()
41_TRUST_CA_PATH = os.path.join(constants.SSL_TRUST_CA_DIR,
42 f"{_CA_NAME}.crt")
43_CERT_CRT_EXT = ";".join(f"echo \"{ext}\"" for ext in [
44 "keyUsage = critical, digitalSignature, keyEncipherment",
45 "extendedKeyUsage = serverAuth",
46 "subjectAltName = DNS.1:localhost, IP.1:0.0.0.0, IP.2:::1"])
47
48# Generate a Root SSL Certificate.
49_CA_CMD = (f"openssl req -new -x509 -days 9999 -newkey rsa:2048 "
50 f"-sha256 -nodes -keyout \"{_CA_KEY_PATH}\" "
51 f"-out \"{_CA_CRT_PATH}\" -extensions v3_ca "
52 f"-subj \"{_CA_SUBJ}\" -addext \"{_CA_EXT}\"")
53
54# Trust the Root SSL Certificate.
55_TRUST_CA_COPY_CMD = f"sudo cp {_CA_CRT_PATH} {_TRUST_CA_PATH}"
56_UPDATE_TRUST_CA_CMD = "sudo update-ca-certificates"
57_TRUST_CHROME_CMD = (
58 "certutil -d sql:$HOME/.pki/nssdb -A -t TC "
59 f"-n \"{_CA_NAME}\" -i \"{_TRUST_CA_PATH}\"")
60
61# Generate an SSL SAN Certificate with the Root Certificate.
62_CERT_KEY_CMD = f"openssl genrsa -out \"{_CERT_KEY_PATH}\" 2048"
63_CERT_CSR_CMD = (f"openssl req -new -key \"{_CERT_KEY_PATH}\" "
64 f"-out \"{_CERT_CSR_PATH}\" -subj \"{_CERT_SUBJ}\"")
65_CERT_CRT_CMD = (
66 f"openssl x509 -req -days 9999 -in \"{_CERT_CSR_PATH}\" "
67 f"-CA \"{_CA_CRT_PATH}\" -CAkey \"{_CA_KEY_PATH}\" "
68 f"-CAcreateserial -out \"{_CERT_CRT_PATH}\" "
69 f"-extfile <({_CERT_CRT_EXT};)")
70
71# UnInstall the Root SSL Certificate.
72_UNDO_TRUST_CA_CMD = f"sudo rm {_TRUST_CA_PATH}"
73_UNDO_TRUST_CHROME_CMD = f"certutil -D -d sql:$HOME/.pki/nssdb -n \"{_CA_NAME}\""
74
75
76def Install():
77 """Install Root SSL Certificates by the openssl tool.
78
79 Generates a Root SSL Certificates and setup the host environment
80 to build a secure browser for WebRTC AVD.
81
82 Returns:
83 True when the Root SSL Certificates are generated and setup.
84 """
chojoyce32ee70e2022-02-11 12:39:53 +080085 if os.path.isdir(_CERT_DIR):
86 shutil.rmtree(_CERT_DIR)
87 os.mkdir(_CERT_DIR)
chojoyceb0817032022-01-12 18:29:36 +080088
89 if os.path.exists(_TRUST_CA_PATH):
90 UnInstall()
91
chojoyce32ee70e2022-02-11 12:39:53 +080092 utils.Popen(_CA_CMD, shell=True)
93 utils.Popen(_TRUST_CA_COPY_CMD, shell=True)
94 utils.Popen(_UPDATE_TRUST_CA_CMD, shell=True)
95 utils.Popen(_TRUST_CHROME_CMD, shell=True)
chojoyceb0817032022-01-12 18:29:36 +080096
97 return IsRootCAReady()
98
99
100def AllocateLocalHostCert():
101 """Allocate localhost certificate by the openssl tool.
102
103 Generate an SSL SAN Certificate with the Root Certificate.
104
105 Returns:
106 True if the certificates is exist.
107 """
108 if not IsRootCAReady():
109 logger.debug("Can't load CA files.")
110 return False
111
112 if not os.path.exists(_CERT_KEY_PATH):
113 utils.Popen(_CERT_KEY_CMD, shell=True)
114 if not os.path.exists(_CERT_CSR_PATH):
115 utils.Popen(_CERT_CSR_CMD, shell=True)
116 if not os.path.exists(_CERT_CRT_PATH):
117 utils.Popen(_CERT_CRT_CMD, shell=True)
118
119 return IsCertificateReady()
120
121
122def IsRootCAReady():
123 """Check if the Root SSL Certificates are all ready.
124
125 Returns:
126 True if the Root SSL Certificates are exist.
127 """
128 for cert_file_name in [_CA_KEY_PATH, _CA_CRT_PATH, _TRUST_CA_PATH]:
129 if not os.path.exists(cert_file_name):
130 logger.debug("Root SSL Certificate: %s, does not exist",
131 cert_file_name)
132 return False
133
134 if not filecmp.cmp(_CA_CRT_PATH, _TRUST_CA_PATH):
135 logger.debug("The trusted CA %s file is not the same with %s ",
136 _TRUST_CA_PATH, _CA_CRT_PATH)
137 return False
138 return True
139
140
141def IsCertificateReady():
142 """Check if the SSL SAN Certificates files are all ready.
143
144 Returns:
145 True if the SSL SAN Certificates files existed.
146 """
147 for cert_file_name in [_CERT_KEY_PATH, _CERT_CRT_PATH]:
148 if not os.path.exists(cert_file_name):
149 logger.debug("SSL SAN Certificate: %s, does not exist",
150 cert_file_name)
151 return False
152 return True
153
154
155def UnInstall():
156 """Uninstall a Root SSL Certificate.
157
158 Undo the Root SSL Certificate host setup.
159 """
160 utils.Popen(_UNDO_TRUST_CA_CMD, shell=True)
161 utils.Popen(_UPDATE_TRUST_CA_CMD, shell=True)
162 utils.Popen(_UNDO_TRUST_CHROME_CMD, shell=True)