blob: 8b167d7b0c90d8ee810590ce14153aacc2dec516 [file] [log] [blame]
Geremy Condra3d33c262012-05-06 18:32:19 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.content.Context;
20import android.content.ContentResolver;
21import android.database.ContentObserver;
22import android.os.Binder;
23import android.os.FileUtils;
24import android.provider.Settings;
25import android.util.Slog;
26
27import java.io.File;
28import java.io.FileOutputStream;
29import java.io.IOException;
30
31import libcore.io.IoUtils;
32
33/**
34 * <p>CertBlacklister provides a simple mechanism for updating the platform blacklists for SSL
35 * certificate public keys and serial numbers.
36 */
37public class CertBlacklister extends Binder {
38
39 private static final String TAG = "CertBlacklister";
40
41 private static final String BLACKLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
42
43 public static final String PUBKEY_PATH = BLACKLIST_ROOT + "pubkey_blacklist.txt";
44 public static final String SERIAL_PATH = BLACKLIST_ROOT + "serial_blacklist.txt";
45
46 public static final String PUBKEY_BLACKLIST_KEY = "pubkey_blacklist";
47 public static final String SERIAL_BLACKLIST_KEY = "serial_blacklist";
48
49 private static class BlacklistObserver extends ContentObserver {
50
51 private final String mKey;
52 private final String mName;
53 private final String mPath;
54 private final File mTmpDir;
55 private final ContentResolver mContentResolver;
56
57 public BlacklistObserver(String key, String name, String path, ContentResolver cr) {
58 super(null);
59 mKey = key;
60 mName = name;
61 mPath = path;
62 mTmpDir = new File(mPath).getParentFile();
63 mContentResolver = cr;
64 }
65
66 @Override
67 public void onChange(boolean selfChange) {
68 super.onChange(selfChange);
69 writeBlacklist();
70 }
71
72 public String getValue() {
73 return Settings.Secure.getString(mContentResolver, mKey);
74 }
75
76 private void writeBlacklist() {
77 new Thread("BlacklistUpdater") {
78 public void run() {
79 synchronized(mTmpDir) {
80 String blacklist = getValue();
81 if (blacklist != null) {
82 Slog.i(TAG, "Certificate blacklist changed, updating...");
83 FileOutputStream out = null;
84 try {
85 // create a temporary file
86 File tmp = File.createTempFile("journal", "", mTmpDir);
87 // mark it -rw-r--r--
88 tmp.setReadable(true, false);
89 // write to it
90 out = new FileOutputStream(tmp);
91 out.write(blacklist.getBytes());
92 // sync to disk
93 FileUtils.sync(out);
94 // atomic rename
95 tmp.renameTo(new File(mPath));
96 Slog.i(TAG, "Certificate blacklist updated");
97 } catch (IOException e) {
98 Slog.e(TAG, "Failed to write blacklist", e);
99 } finally {
100 IoUtils.closeQuietly(out);
101 }
102 }
103 }
104 }
105 }.start();
106 }
107 }
108
109 public CertBlacklister(Context context) {
110 registerObservers(context.getContentResolver());
111 }
112
113 private BlacklistObserver buildPubkeyObserver(ContentResolver cr) {
114 return new BlacklistObserver(PUBKEY_BLACKLIST_KEY,
115 "pubkey",
116 PUBKEY_PATH,
117 cr);
118 }
119
120 private BlacklistObserver buildSerialObserver(ContentResolver cr) {
121 return new BlacklistObserver(SERIAL_BLACKLIST_KEY,
122 "serial",
123 SERIAL_PATH,
124 cr);
125 }
126
127 private void registerObservers(ContentResolver cr) {
128 // set up the public key blacklist observer
129 cr.registerContentObserver(
130 Settings.Secure.getUriFor(PUBKEY_BLACKLIST_KEY),
131 true,
132 buildPubkeyObserver(cr)
133 );
134
135 // set up the serial number blacklist observer
136 cr.registerContentObserver(
137 Settings.Secure.getUriFor(SERIAL_BLACKLIST_KEY),
138 true,
139 buildSerialObserver(cr)
140 );
141 }
142}