1 /* 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 17 package com.android.server; 18 19 import android.content.Context; 20 import android.content.ContentResolver; 21 import android.database.ContentObserver; 22 import android.os.Binder; 23 import android.os.FileUtils; 24 import android.provider.Settings; 25 import android.util.Slog; 26 27 import java.io.File; 28 import java.io.FileOutputStream; 29 import java.io.IOException; 30 31 import 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 */ 37 public 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 } 143