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