xref: /aosp_15_r20/tools/acloud/setup/mkcert.py (revision 800a58d989c669b8eb8a71d8df53b1ba3d411444)
1*800a58d9SAndroid Build Coastguard Worker# Copyright 2022 - The Android Open Source Project
2*800a58d9SAndroid Build Coastguard Worker#
3*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*800a58d9SAndroid Build Coastguard Worker#
7*800a58d9SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*800a58d9SAndroid Build Coastguard Worker#
9*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*800a58d9SAndroid Build Coastguard Worker# limitations under the License.
14*800a58d9SAndroid Build Coastguard Workerr"""Mkcert entry point.
15*800a58d9SAndroid Build Coastguard Worker
16*800a58d9SAndroid Build Coastguard WorkerMkcert will handle the SSL certificates process to secure WEB browser of
17*800a58d9SAndroid Build Coastguard Workera local or remote instance of an Android Virtual Device.
18*800a58d9SAndroid Build Coastguard Worker"""
19*800a58d9SAndroid Build Coastguard Worker
20*800a58d9SAndroid Build Coastguard Workerimport filecmp
21*800a58d9SAndroid Build Coastguard Workerimport logging
22*800a58d9SAndroid Build Coastguard Workerimport os
23*800a58d9SAndroid Build Coastguard Workerimport platform
24*800a58d9SAndroid Build Coastguard Workerimport shutil
25*800a58d9SAndroid Build Coastguard Workerimport stat
26*800a58d9SAndroid Build Coastguard Worker
27*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal import constants
28*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import utils
29*800a58d9SAndroid Build Coastguard Worker
30*800a58d9SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
31*800a58d9SAndroid Build Coastguard Worker
32*800a58d9SAndroid Build Coastguard Worker_CA_NAME = constants.SSL_CA_NAME
33*800a58d9SAndroid Build Coastguard Worker_CERT_DIR = os.path.join(os.path.expanduser("~"), constants.SSL_DIR)
34*800a58d9SAndroid Build Coastguard Worker_CA_KEY_PATH = os.path.join(_CERT_DIR, f"{_CA_NAME}.key")
35*800a58d9SAndroid Build Coastguard Worker_CA_CRT_PATH = os.path.join(_CERT_DIR, f"{_CA_NAME}.pem")
36*800a58d9SAndroid Build Coastguard Worker_CERT_KEY_PATH = os.path.join(_CERT_DIR, "server.key")
37*800a58d9SAndroid Build Coastguard Worker_CERT_CSR_PATH = os.path.join(_CERT_DIR, "server.csr")
38*800a58d9SAndroid Build Coastguard Worker_CERT_CRT_PATH = os.path.join(_CERT_DIR, "server.crt")
39*800a58d9SAndroid Build Coastguard Worker_CA_EXT = "keyUsage=critical,keyCertSign"
40*800a58d9SAndroid Build Coastguard Worker_CA_SUBJ="/OU=acloud/O=acloud development CA/CN=localhost"
41*800a58d9SAndroid Build Coastguard Worker_CERT_SUBJ = "/OU=%s/O=acloud development CA" % platform.node()
42*800a58d9SAndroid Build Coastguard Worker_TRUST_CA_PATH = os.path.join(constants.SSL_TRUST_CA_DIR,
43*800a58d9SAndroid Build Coastguard Worker                              f"{_CA_NAME}.crt")
44*800a58d9SAndroid Build Coastguard Worker_CERT_CRT_EXT = ";".join(f"echo \"{ext}\"" for ext in [
45*800a58d9SAndroid Build Coastguard Worker    "keyUsage = critical, digitalSignature, keyEncipherment",
46*800a58d9SAndroid Build Coastguard Worker    "extendedKeyUsage = serverAuth",
47*800a58d9SAndroid Build Coastguard Worker    "subjectAltName = DNS.1:localhost, IP.1:0.0.0.0, IP.2:::1"])
48*800a58d9SAndroid Build Coastguard Worker
49*800a58d9SAndroid Build Coastguard Worker# Generate a Root SSL Certificate.
50*800a58d9SAndroid Build Coastguard Worker_CA_CMD = (f"openssl req -new -x509 -days 9999 -newkey rsa:2048 "
51*800a58d9SAndroid Build Coastguard Worker           f"-sha256 -nodes -keyout \"{_CA_KEY_PATH}\" "
52*800a58d9SAndroid Build Coastguard Worker           f"-out \"{_CA_CRT_PATH}\" -extensions v3_ca "
53*800a58d9SAndroid Build Coastguard Worker           f"-subj \"{_CA_SUBJ}\" -addext \"{_CA_EXT}\"")
54*800a58d9SAndroid Build Coastguard Worker
55*800a58d9SAndroid Build Coastguard Worker# Trust the Root SSL Certificate.
56*800a58d9SAndroid Build Coastguard Worker_TRUST_CA_COPY_CMD = f"sudo cp -p {_CA_CRT_PATH} {_TRUST_CA_PATH}"
57*800a58d9SAndroid Build Coastguard Worker_UPDATE_TRUST_CA_CMD = "sudo update-ca-certificates"
58*800a58d9SAndroid Build Coastguard Worker_TRUST_CHROME_CMD = (
59*800a58d9SAndroid Build Coastguard Worker    "certutil -d sql:$HOME/.pki/nssdb -A -t TC "
60*800a58d9SAndroid Build Coastguard Worker    f"-n \"{_CA_NAME}\" -i \"{_TRUST_CA_PATH}\"")
61*800a58d9SAndroid Build Coastguard Worker
62*800a58d9SAndroid Build Coastguard Worker# Generate an SSL SAN Certificate with the Root Certificate.
63*800a58d9SAndroid Build Coastguard Worker_CERT_KEY_CMD = f"openssl genrsa -out \"{_CERT_KEY_PATH}\" 2048"
64*800a58d9SAndroid Build Coastguard Worker_CERT_CSR_CMD = (f"openssl req -new -key \"{_CERT_KEY_PATH}\" "
65*800a58d9SAndroid Build Coastguard Worker                 f"-out \"{_CERT_CSR_PATH}\" -subj \"{_CERT_SUBJ}\"")
66*800a58d9SAndroid Build Coastguard Worker_CERT_CRT_CMD = (
67*800a58d9SAndroid Build Coastguard Worker    f"openssl x509 -req -days 9999 -in \"{_CERT_CSR_PATH}\" "
68*800a58d9SAndroid Build Coastguard Worker    f"-CA \"{_CA_CRT_PATH}\" -CAkey \"{_CA_KEY_PATH}\" "
69*800a58d9SAndroid Build Coastguard Worker    f"-CAcreateserial -out \"{_CERT_CRT_PATH}\" "
70*800a58d9SAndroid Build Coastguard Worker    f"-extfile <({_CERT_CRT_EXT};)")
71*800a58d9SAndroid Build Coastguard Worker
72*800a58d9SAndroid Build Coastguard Worker# UnInstall the Root SSL Certificate.
73*800a58d9SAndroid Build Coastguard Worker_UNDO_TRUST_CA_CMD = f"sudo rm {_TRUST_CA_PATH}"
74*800a58d9SAndroid Build Coastguard Worker_UNDO_TRUST_CHROME_CMD = f"certutil -D -d sql:$HOME/.pki/nssdb -n \"{_CA_NAME}\""
75*800a58d9SAndroid Build Coastguard Worker
76*800a58d9SAndroid Build Coastguard Worker
77*800a58d9SAndroid Build Coastguard Workerdef Install():
78*800a58d9SAndroid Build Coastguard Worker    """Install Root SSL Certificates by the openssl tool.
79*800a58d9SAndroid Build Coastguard Worker
80*800a58d9SAndroid Build Coastguard Worker    Generates a Root SSL Certificates and setup the host environment
81*800a58d9SAndroid Build Coastguard Worker    to build a secure browser for WebRTC AVD.
82*800a58d9SAndroid Build Coastguard Worker
83*800a58d9SAndroid Build Coastguard Worker    Returns:
84*800a58d9SAndroid Build Coastguard Worker        True when the Root SSL Certificates are generated and setup.
85*800a58d9SAndroid Build Coastguard Worker    """
86*800a58d9SAndroid Build Coastguard Worker    if os.path.isdir(_CERT_DIR):
87*800a58d9SAndroid Build Coastguard Worker        shutil.rmtree(_CERT_DIR)
88*800a58d9SAndroid Build Coastguard Worker    os.mkdir(_CERT_DIR)
89*800a58d9SAndroid Build Coastguard Worker
90*800a58d9SAndroid Build Coastguard Worker    if os.path.exists(_TRUST_CA_PATH):
91*800a58d9SAndroid Build Coastguard Worker        UnInstall()
92*800a58d9SAndroid Build Coastguard Worker
93*800a58d9SAndroid Build Coastguard Worker    utils.Popen(_CA_CMD, shell=True)
94*800a58d9SAndroid Build Coastguard Worker    # The rootCA.pem file should grant READ permission to others.
95*800a58d9SAndroid Build Coastguard Worker    if not os.stat(_CA_CRT_PATH).st_mode & stat.S_IROTH:
96*800a58d9SAndroid Build Coastguard Worker        os.chmod(_CA_CRT_PATH, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
97*800a58d9SAndroid Build Coastguard Worker    utils.Popen(_TRUST_CA_COPY_CMD, shell=True)
98*800a58d9SAndroid Build Coastguard Worker    utils.Popen(_UPDATE_TRUST_CA_CMD, shell=True)
99*800a58d9SAndroid Build Coastguard Worker    utils.Popen(_TRUST_CHROME_CMD, shell=True)
100*800a58d9SAndroid Build Coastguard Worker
101*800a58d9SAndroid Build Coastguard Worker    return IsRootCAReady()
102*800a58d9SAndroid Build Coastguard Worker
103*800a58d9SAndroid Build Coastguard Worker
104*800a58d9SAndroid Build Coastguard Workerdef AllocateLocalHostCert():
105*800a58d9SAndroid Build Coastguard Worker    """Allocate localhost certificate by the openssl tool.
106*800a58d9SAndroid Build Coastguard Worker
107*800a58d9SAndroid Build Coastguard Worker    Generate an SSL SAN Certificate with the Root Certificate.
108*800a58d9SAndroid Build Coastguard Worker
109*800a58d9SAndroid Build Coastguard Worker    Returns:
110*800a58d9SAndroid Build Coastguard Worker        True if the certificates is exist.
111*800a58d9SAndroid Build Coastguard Worker    """
112*800a58d9SAndroid Build Coastguard Worker    if not IsRootCAReady():
113*800a58d9SAndroid Build Coastguard Worker        logger.debug("Can't load CA files.")
114*800a58d9SAndroid Build Coastguard Worker        return False
115*800a58d9SAndroid Build Coastguard Worker
116*800a58d9SAndroid Build Coastguard Worker    if not os.path.exists(_CERT_KEY_PATH):
117*800a58d9SAndroid Build Coastguard Worker        utils.Popen(_CERT_KEY_CMD, shell=True)
118*800a58d9SAndroid Build Coastguard Worker    if not os.path.exists(_CERT_CSR_PATH):
119*800a58d9SAndroid Build Coastguard Worker        utils.Popen(_CERT_CSR_CMD, shell=True)
120*800a58d9SAndroid Build Coastguard Worker    if not os.path.exists(_CERT_CRT_PATH):
121*800a58d9SAndroid Build Coastguard Worker        utils.Popen(_CERT_CRT_CMD, shell=True)
122*800a58d9SAndroid Build Coastguard Worker
123*800a58d9SAndroid Build Coastguard Worker    return IsCertificateReady()
124*800a58d9SAndroid Build Coastguard Worker
125*800a58d9SAndroid Build Coastguard Worker
126*800a58d9SAndroid Build Coastguard Workerdef IsRootCAReady():
127*800a58d9SAndroid Build Coastguard Worker    """Check if the Root SSL Certificates are all ready.
128*800a58d9SAndroid Build Coastguard Worker
129*800a58d9SAndroid Build Coastguard Worker    Returns:
130*800a58d9SAndroid Build Coastguard Worker        True if the Root SSL Certificates are exist.
131*800a58d9SAndroid Build Coastguard Worker    """
132*800a58d9SAndroid Build Coastguard Worker    for cert_file_name in [_CA_KEY_PATH, _CA_CRT_PATH, _TRUST_CA_PATH]:
133*800a58d9SAndroid Build Coastguard Worker        if not os.path.exists(cert_file_name):
134*800a58d9SAndroid Build Coastguard Worker            logger.debug("Root SSL Certificate: %s, does not exist",
135*800a58d9SAndroid Build Coastguard Worker                         cert_file_name)
136*800a58d9SAndroid Build Coastguard Worker            return False
137*800a58d9SAndroid Build Coastguard Worker    # TODO: this check can be delete when the mkcert mechanism is stable.
138*800a58d9SAndroid Build Coastguard Worker    if not os.stat(_TRUST_CA_PATH).st_mode & stat.S_IROTH:
139*800a58d9SAndroid Build Coastguard Worker        return False
140*800a58d9SAndroid Build Coastguard Worker
141*800a58d9SAndroid Build Coastguard Worker    if not filecmp.cmp(_CA_CRT_PATH, _TRUST_CA_PATH):
142*800a58d9SAndroid Build Coastguard Worker        logger.debug("The trusted CA %s file is not the same with %s ",
143*800a58d9SAndroid Build Coastguard Worker                     _TRUST_CA_PATH, _CA_CRT_PATH)
144*800a58d9SAndroid Build Coastguard Worker        return False
145*800a58d9SAndroid Build Coastguard Worker    return True
146*800a58d9SAndroid Build Coastguard Worker
147*800a58d9SAndroid Build Coastguard Worker
148*800a58d9SAndroid Build Coastguard Workerdef IsCertificateReady():
149*800a58d9SAndroid Build Coastguard Worker    """Check if the SSL SAN Certificates files are all ready.
150*800a58d9SAndroid Build Coastguard Worker
151*800a58d9SAndroid Build Coastguard Worker    Returns:
152*800a58d9SAndroid Build Coastguard Worker        True if the SSL SAN Certificates files existed.
153*800a58d9SAndroid Build Coastguard Worker    """
154*800a58d9SAndroid Build Coastguard Worker    for cert_file_name in [_CERT_KEY_PATH, _CERT_CRT_PATH]:
155*800a58d9SAndroid Build Coastguard Worker        if not os.path.exists(cert_file_name):
156*800a58d9SAndroid Build Coastguard Worker            logger.debug("SSL SAN Certificate: %s, does not exist",
157*800a58d9SAndroid Build Coastguard Worker                         cert_file_name)
158*800a58d9SAndroid Build Coastguard Worker            return False
159*800a58d9SAndroid Build Coastguard Worker    return True
160*800a58d9SAndroid Build Coastguard Worker
161*800a58d9SAndroid Build Coastguard Worker
162*800a58d9SAndroid Build Coastguard Workerdef UnInstall():
163*800a58d9SAndroid Build Coastguard Worker    """Uninstall a Root SSL Certificate.
164*800a58d9SAndroid Build Coastguard Worker
165*800a58d9SAndroid Build Coastguard Worker    Undo the Root SSL Certificate host setup.
166*800a58d9SAndroid Build Coastguard Worker    """
167*800a58d9SAndroid Build Coastguard Worker    utils.Popen(_UNDO_TRUST_CA_CMD, shell=True)
168*800a58d9SAndroid Build Coastguard Worker    utils.Popen(_UPDATE_TRUST_CA_CMD, shell=True)
169*800a58d9SAndroid Build Coastguard Worker    utils.Popen(_UNDO_TRUST_CHROME_CMD, shell=True)
170