1088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee/*
2088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee * Copyright (C) 2017 The Android Open Source Project
3088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee *
4088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee * Licensed under the Apache License, Version 2.0 (the "License");
5088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee * you may not use this file except in compliance with the License.
6088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee * You may obtain a copy of the License at
7088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee *
8088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee *      http://www.apache.org/licenses/LICENSE-2.0
9088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee *
10088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee * Unless required by applicable law or agreed to in writing, software
11088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee * distributed under the License is distributed on an "AS IS" BASIS,
12088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee * See the License for the specific language governing permissions and
14088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee * limitations under the License.
15088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee */
16088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
17088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leepackage com.android.server.devicepolicy;
18088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
19088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.app.Notification;
20088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.app.NotificationManager;
21088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.app.PendingIntent;
22088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.content.BroadcastReceiver;
23088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.content.Context;
24088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.content.Intent;
25088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.content.IntentFilter;
26088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.content.pm.ActivityInfo;
27088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.content.pm.PackageManager;
28088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.content.res.Resources;
29088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.graphics.Color;
30088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.os.Build;
31088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.os.Handler;
32088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.os.RemoteException;
33088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.os.UserHandle;
34088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.os.UserManager;
35088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.os.storage.StorageManager;
36088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.provider.Settings;
37088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.security.Credentials;
38088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.security.KeyChain;
39088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.security.KeyChain.KeyChainConnection;
40088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport android.util.Log;
41088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
42282cfefea0fbbd299839e353e6d30affdcd4a55cChris Wrenimport com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
43088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport com.android.internal.notification.SystemNotificationChannels;
44088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport com.android.internal.R;
45088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
46088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport java.io.ByteArrayInputStream;
47088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport java.io.IOException;
48088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport java.security.cert.CertificateException;
49088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport java.security.cert.CertificateFactory;
50088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport java.security.cert.X509Certificate;
51088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport java.util.List;
52088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leeimport java.util.Set;
53088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
54088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Leepublic class CertificateMonitor {
55088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    protected static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
56282cfefea0fbbd299839e353e6d30affdcd4a55cChris Wren    protected static final int MONITORING_CERT_NOTIFICATION_ID = SystemMessage.NOTE_SSL_CERT_INFO;
57088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
58088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    private final DevicePolicyManagerService mService;
59088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    private final DevicePolicyManagerService.Injector mInjector;
60088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    private final Handler mHandler;
61088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
62088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    public CertificateMonitor(final DevicePolicyManagerService service,
63088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            final DevicePolicyManagerService.Injector injector, final Handler handler) {
64088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        mService = service;
65088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        mInjector = injector;
66088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        mHandler = handler;
67088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
68088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        // Broadcast filter for changes to the trusted certificate store. Listens on the background
69088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        // handler to avoid blocking time-critical tasks on the main handler thread.
70088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        IntentFilter filter = new IntentFilter();
71088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        filter.addAction(Intent.ACTION_USER_STARTED);
72088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        filter.addAction(Intent.ACTION_USER_UNLOCKED);
73088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
74088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
75088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        mInjector.mContext.registerReceiverAsUser(
76088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                mRootCaReceiver, UserHandle.ALL, filter, null, mHandler);
77088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    }
78088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
79088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    public String installCaCert(final UserHandle userHandle, byte[] certBuffer) {
80088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        // Convert certificate data from X509 format to PEM.
81088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        byte[] pemCert;
82088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        try {
83088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            X509Certificate cert = parseCert(certBuffer);
84088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            pemCert = Credentials.convertToPem(cert);
85088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } catch (CertificateException | IOException ce) {
86088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Log.e(LOG_TAG, "Problem converting cert", ce);
87088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            return null;
88088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
89088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
90088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        try (KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(userHandle)) {
91088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            return keyChainConnection.getService().installCaCertificate(pemCert);
92088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } catch (RemoteException e) {
93088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Log.e(LOG_TAG, "installCaCertsToKeyChain(): ", e);
94088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } catch (InterruptedException e1) {
95088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
96088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Thread.currentThread().interrupt();
97088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
98088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        return null;
99088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    }
100088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
101088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    public void uninstallCaCerts(final UserHandle userHandle, final String[] aliases) {
102088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        try (KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(userHandle)) {
103088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            for (int i = 0 ; i < aliases.length; i++) {
104088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                keyChainConnection.getService().deleteCaCertificate(aliases[i]);
105088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            }
106088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } catch (RemoteException e) {
107088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
108088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } catch (InterruptedException ie) {
109088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
110088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Thread.currentThread().interrupt();
111088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
112088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    }
113088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
114088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    public List<String> getInstalledCaCertificates(UserHandle userHandle)
115088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            throws RemoteException, RuntimeException {
116088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
117088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            return conn.getService().getUserCaAliases().getList();
118088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } catch (InterruptedException e) {
119088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Thread.currentThread().interrupt();
120088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            return null;
121088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } catch (AssertionError e) {
122088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            throw new RuntimeException(e);
123088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
124088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    }
125088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
126088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    public void onCertificateApprovalsChanged(int userId) {
127088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        mHandler.post(() -> updateInstalledCertificates(UserHandle.of(userId)));
128088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    }
129088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
130088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    /**
131088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee     * Broadcast receiver for changes to the trusted certificate store.
132088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee     */
133088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    private final BroadcastReceiver mRootCaReceiver = new BroadcastReceiver() {
134088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        @Override
135088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        public void onReceive(Context context, Intent intent) {
136088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            if (StorageManager.inCryptKeeperBounce()) {
137088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                return;
138088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            }
139088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
140088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            updateInstalledCertificates(UserHandle.of(userId));
141088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
142088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    };
143088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
144088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    private void updateInstalledCertificates(final UserHandle userHandle) {
145088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        if (!mInjector.getUserManager().isUserUnlocked(userHandle.getIdentifier())) {
146088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            return;
147088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
148088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
149088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        final List<String> installedCerts;
150088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        try {
151088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            installedCerts = getInstalledCaCertificates(userHandle);
152088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } catch (RemoteException | RuntimeException e) {
153088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e);
154088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            return;
155088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
156088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        mService.onInstalledCertificatesChanged(userHandle, installedCerts);
157088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
158088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        final int pendingCertificateCount =
159088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                installedCerts.size() - mService.getAcceptedCaCertificates(userHandle).size();
160088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        if (pendingCertificateCount != 0) {
161088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            final Notification noti = buildNotification(userHandle, pendingCertificateCount);
162088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            mInjector.getNotificationManager().notifyAsUser(
163088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                    LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
164088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } else {
165088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            mInjector.getNotificationManager().cancelAsUser(
166088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                    LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, userHandle);
167088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
168088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    }
169088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
170088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    private Notification buildNotification(UserHandle userHandle, int pendingCertificateCount) {
171088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        final Context userContext;
172088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        try {
173088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            userContext = mInjector.createContextAsUser(userHandle);
174088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } catch (PackageManager.NameNotFoundException e) {
175088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e);
176088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            return null;
177088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
178088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
179088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        final Resources resources = mInjector.getResources();
180088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        final int smallIconId;
181088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        final String contentText;
182088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
183088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        int parentUserId = userHandle.getIdentifier();
184088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
185088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        if (mService.getProfileOwner(userHandle.getIdentifier()) != null) {
186088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            contentText = resources.getString(R.string.ssl_ca_cert_noti_managed,
187088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                    mService.getProfileOwnerName(userHandle.getIdentifier()));
188088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            smallIconId = R.drawable.stat_sys_certificate_info;
189088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            parentUserId = mService.getProfileParentId(userHandle.getIdentifier());
190088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } else if (mService.getDeviceOwnerUserId() == userHandle.getIdentifier()) {
191088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            final String ownerName = mService.getDeviceOwnerName();
192088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            contentText = resources.getString(R.string.ssl_ca_cert_noti_managed,
193088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                    mService.getDeviceOwnerName());
194088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            smallIconId = R.drawable.stat_sys_certificate_info;
195088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        } else {
196088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            contentText = resources.getString(R.string.ssl_ca_cert_noti_by_unknown);
197088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            smallIconId = android.R.drawable.stat_sys_warning;
198088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
199088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
200088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        // Create an intent to launch an activity showing information about the certificate.
201088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
202088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
203088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        dialogIntent.putExtra(Settings.EXTRA_NUMBER_OF_CERTIFICATES, pendingCertificateCount);
204088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        dialogIntent.putExtra(Intent.EXTRA_USER_ID, userHandle.getIdentifier());
205088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
206088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        // The intent should only be allowed to resolve to a system app.
207088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        ActivityInfo targetInfo = dialogIntent.resolveActivityInfo(
208088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                mInjector.getPackageManager(), PackageManager.MATCH_SYSTEM_ONLY);
209088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        if (targetInfo != null) {
210088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee            dialogIntent.setComponent(targetInfo.getComponentName());
211088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        }
212088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
213088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        PendingIntent notifyIntent = mInjector.pendingIntentGetActivityAsUser(userContext, 0,
214088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                dialogIntent, PendingIntent.FLAG_UPDATE_CURRENT, null,
215088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                UserHandle.of(parentUserId));
216088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
217088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        return new Notification.Builder(userContext, SystemNotificationChannels.SECURITY)
218088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                .setSmallIcon(smallIconId)
219088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                .setContentTitle(resources.getQuantityText(R.plurals.ssl_ca_cert_warning,
220088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                        pendingCertificateCount))
221088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                .setContentText(contentText)
222088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                .setContentIntent(notifyIntent)
223088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                .setShowWhen(false)
224088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                .setColor(R.color.system_notification_accent_color)
225088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                .build();
226088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    }
227088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee
228088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    private static X509Certificate parseCert(byte[] certBuffer) throws CertificateException {
229088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
230088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee        return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
231088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee                certBuffer));
232088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee    }
233088d7aa9c1e9b73ea9dce1616b4958f0c41ca05eRobin Lee}
234