1adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh/* 2adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * Copyright (C) 2009 The Android Open Source Project 3adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * 4adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 5adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * you may not use this file except in compliance with the License. 6adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * You may obtain a copy of the License at 7adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * 8adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * http://www.apache.org/licenses/LICENSE-2.0 9adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * 10adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software 11adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS, 12adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * See the License for the specific language governing permissions and 14adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * limitations under the License. 15adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh */ 16adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 17adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <stdio.h> 18adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <stdint.h> 19adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <string.h> 20adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <unistd.h> 21adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <signal.h> 22adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <errno.h> 23adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <dirent.h> 24adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <fcntl.h> 25adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <limits.h> 26adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <sys/types.h> 27adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <sys/socket.h> 28adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <sys/stat.h> 29adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <sys/time.h> 30adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <arpa/inet.h> 31adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 32adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <openssl/aes.h> 33adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <openssl/evp.h> 34adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <openssl/md5.h> 35adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 36adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#define LOG_TAG "keystore" 37adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <cutils/log.h> 38adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <cutils/sockets.h> 39adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include <private/android_filesystem_config.h> 40adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 41adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#include "keystore.h" 42adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 43adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh/* KeyStore is a secured storage for key-value pairs. In this implementation, 44adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * each file stores one key-value pair. Keys are encoded in file names, and 45adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * values are encrypted with checksums. The encryption key is protected by a 46adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * user-defined password. To keep things simple, buffers are always larger than 47adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * the maximum space we needed, so boundary checks on buffers are omitted. */ 48adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 494165dd21592c958bacc97043d56b1ea914ab94c9Chia-chi Yeh#define KEY_SIZE ((NAME_MAX - 15) / 2) 50adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#define VALUE_SIZE 32768 51adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#define PASSWORD_SIZE VALUE_SIZE 52adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 53adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh/* Here is the encoding of keys. This is necessary in order to allow arbitrary 54adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * characters in keys. Characters in [0-~] are not encoded. Others are encoded 55adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * into two bytes. The first byte is one of [+-.] which represents the first 56adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * two bits of the character. The second byte encodes the rest of the bits into 57adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * [0-o]. Therefore in the worst case the length of a key gets doubled. Note 58adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * that Base64 cannot be used here due to the need of prefix match on keys. */ 59adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 60adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int encode_key(char *out, uint8_t *in, int length) 61adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 62adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int i; 63adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh for (i = length; i > 0; --i, ++in, ++out) { 64adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (*in >= '0' && *in <= '~') { 65adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh *out = *in; 66adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } else { 67adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh *out = '+' + (*in >> 6); 68adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh *++out = '0' + (*in & 0x3F); 69adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh ++length; 70adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 71adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 72adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh *out = 0; 73adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return length; 74adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 75adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 76adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int decode_key(uint8_t *out, char *in, int length) 77adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 78adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int i; 79adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh for (i = 0; i < length; ++i, ++in, ++out) { 80adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (*in >= '0' && *in <= '~') { 81adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh *out = *in; 82adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } else { 83adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh *out = (*in - '+') << 6; 84adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh *out |= (*++in - '0') & 0x3F; 85adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh --length; 86adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 87adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 88adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh *out = 0; 89adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return length; 90adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 91adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 92adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh/* Here is the protocol used in both requests and responses: 93adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * code [length_1 message_1 ... length_n message_n] end-of-file 94adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * where code is one byte long and lengths are unsigned 16-bit integers in 95adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * network order. Thus the maximum length of a message is 65535 bytes. */ 96adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 97adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int the_socket = -1; 98adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 99adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int recv_code(int8_t *code) 100adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 101adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return recv(the_socket, code, 1, 0) == 1; 102adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 103adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 104adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int recv_message(uint8_t *message, int length) 105adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 106adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint8_t bytes[2]; 107adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (recv(the_socket, &bytes[0], 1, 0) != 1 || 108adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh recv(the_socket, &bytes[1], 1, 0) != 1) { 109adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return -1; 110adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } else { 111adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int offset = bytes[0] << 8 | bytes[1]; 112adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (length < offset) { 113adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return -1; 114adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 115adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh length = offset; 116adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh offset = 0; 117adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh while (offset < length) { 118adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int n = recv(the_socket, &message[offset], length - offset, 0); 119adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (n <= 0) { 120adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return -1; 121adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 122adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh offset += n; 123adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 124adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 125adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return length; 126adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 127adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 128626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yehstatic int recv_end_of_file() 129626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh{ 130626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh uint8_t byte; 131626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh return recv(the_socket, &byte, 1, 0) == 0; 132626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh} 133626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh 134adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic void send_code(int8_t code) 135adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 136adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh send(the_socket, &code, 1, 0); 137adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 138adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 139adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic void send_message(uint8_t *message, int length) 140adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 141adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint16_t bytes = htons(length); 142adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh send(the_socket, &bytes, 2, 0); 143adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh send(the_socket, message, length, 0); 144adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 145adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 146adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh/* Here is the file format. Values are encrypted by AES CBC, and MD5 is used to 147adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * compute their checksums. To make the files portable, the length is stored in 148adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * network order. Note that the first four bytes are reserved for future use and 149adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * are always set to zero in this implementation. */ 150adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 151adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int the_entropy = -1; 152adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 153adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic struct __attribute__((packed)) { 154adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint32_t reserved; 155adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint8_t vector[AES_BLOCK_SIZE]; 156adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint8_t encrypted[0]; 157adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint8_t digest[MD5_DIGEST_LENGTH]; 158adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint8_t digested[0]; 159adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int32_t length; 160adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE]; 161adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} blob; 162adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 163adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t encrypt_blob(char *name, AES_KEY *aes_key) 164adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 165adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint8_t vector[AES_BLOCK_SIZE]; 166fa4ae74ef7db34ec5efe86e7606271928a876c1cChia-chi Yeh int length; 167adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int fd; 168adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 169adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (read(the_entropy, vector, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) { 170adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return SYSTEM_ERROR; 171adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 172adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 1735fe8598f755bdfd15e96bb2ddcdbe9a41b8173a7Chia-chi Yeh length = blob.length + blob.value - blob.encrypted; 1745fe8598f755bdfd15e96bb2ddcdbe9a41b8173a7Chia-chi Yeh length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE; 175fa4ae74ef7db34ec5efe86e7606271928a876c1cChia-chi Yeh 176adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh blob.length = htonl(blob.length); 1775fe8598f755bdfd15e96bb2ddcdbe9a41b8173a7Chia-chi Yeh MD5(blob.digested, length - (blob.digested - blob.encrypted), blob.digest); 178adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 179adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh memcpy(vector, blob.vector, AES_BLOCK_SIZE); 180adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector, 181adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh AES_ENCRYPT); 182adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 183adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh blob.reserved = 0; 184adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh length += blob.encrypted - (uint8_t *)&blob; 185adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 186adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); 187fa4ae74ef7db34ec5efe86e7606271928a876c1cChia-chi Yeh length -= write(fd, &blob, length); 188adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh close(fd); 189fa4ae74ef7db34ec5efe86e7606271928a876c1cChia-chi Yeh return (length || rename(".tmp", name)) ? SYSTEM_ERROR : NO_ERROR; 190adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 191adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 192adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t decrypt_blob(char *name, AES_KEY *aes_key) 193adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 194adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int fd = open(name, O_RDONLY); 195adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int length; 196adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 197adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (fd == -1) { 198adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR; 199adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 200adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh length = read(fd, &blob, sizeof(blob)); 201adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh close(fd); 202adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 203adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh length -= blob.encrypted - (uint8_t *)&blob; 204adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) { 205adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return VALUE_CORRUPTED; 206adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 207adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 208adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, 209adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh blob.vector, AES_DECRYPT); 210adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh length -= blob.digested - blob.encrypted; 211fa4ae74ef7db34ec5efe86e7606271928a876c1cChia-chi Yeh if (memcmp(blob.digest, MD5(blob.digested, length, NULL), 212fa4ae74ef7db34ec5efe86e7606271928a876c1cChia-chi Yeh MD5_DIGEST_LENGTH)) { 213adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return VALUE_CORRUPTED; 214adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 215adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 216adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh length -= blob.value - blob.digested; 217adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh blob.length = ntohl(blob.length); 218fa4ae74ef7db34ec5efe86e7606271928a876c1cChia-chi Yeh return (blob.length < 0 || blob.length > length) ? VALUE_CORRUPTED : 219fa4ae74ef7db34ec5efe86e7606271928a876c1cChia-chi Yeh NO_ERROR; 220adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 221adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 222adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh/* Here are the actions. Each of them is a function without arguments. All 223adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * information is defined in global variables, which are set properly before 224adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh * performing an action. The number of parameters required by each action is 225c4b144533a9a5d03ee1fbcf27492a8be5737541dChia-chi Yeh * fixed and defined in a table. If the return value of an action is positive, 226c4b144533a9a5d03ee1fbcf27492a8be5737541dChia-chi Yeh * it will be treated as a response code and transmitted to the client. Note 227c4b144533a9a5d03ee1fbcf27492a8be5737541dChia-chi Yeh * that the lengths of parameters are checked when they are received, so 228c4b144533a9a5d03ee1fbcf27492a8be5737541dChia-chi Yeh * boundary checks on parameters are omitted. */ 229adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 230adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#define MAX_PARAM 2 231adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#define MAX_RETRY 4 232adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 233adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic uid_t uid = -1; 234adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t state = UNINITIALIZED; 235adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t retry = MAX_RETRY; 236adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 237adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic struct { 238adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int length; 239adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint8_t value[VALUE_SIZE]; 240adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} params[MAX_PARAM]; 241adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 242adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic AES_KEY encryption_key; 243adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic AES_KEY decryption_key; 244adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 245adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t test() 246adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 247adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return state; 248adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 249adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 250adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t get() 251adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 252adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh char name[NAME_MAX]; 253adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int n = sprintf(name, "%u_", uid); 254adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh encode_key(&name[n], params[0].value, params[0].length); 255adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh n = decrypt_blob(name, &decryption_key); 256adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (n != NO_ERROR) { 257adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return n; 258adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 259adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh send_code(NO_ERROR); 260adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh send_message(blob.value, blob.length); 261adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return -NO_ERROR; 262adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 263adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 264adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t insert() 265adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 266adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh char name[NAME_MAX]; 267adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int n = sprintf(name, "%u_", uid); 268adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh encode_key(&name[n], params[0].value, params[0].length); 269adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh blob.length = params[1].length; 270adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh memcpy(blob.value, params[1].value, params[1].length); 271adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return encrypt_blob(name, &encryption_key); 272adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 273adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 274adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t delete() 275adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 276adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh char name[NAME_MAX]; 277adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int n = sprintf(name, "%u_", uid); 278adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh encode_key(&name[n], params[0].value, params[0].length); 279adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return (unlink(name) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR; 280adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 281adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 282adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t exist() 283adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 284adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh char name[NAME_MAX]; 285adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int n = sprintf(name, "%u_", uid); 286adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh encode_key(&name[n], params[0].value, params[0].length); 287adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (access(name, R_OK) == -1) { 288adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND; 289adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 290adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return NO_ERROR; 291adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 292adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 2931f6802295e2dba50a4549b8a22537dcb4c4dda03Chia-chi Yehstatic int8_t saw() 294adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 295adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh DIR *dir = opendir("."); 296adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh struct dirent *file; 297adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh char name[NAME_MAX]; 298adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int n; 299adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 300adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (!dir) { 301adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return SYSTEM_ERROR; 302adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 303adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh n = sprintf(name, "%u_", uid); 304adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh n += encode_key(&name[n], params[0].value, params[0].length); 305adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh send_code(NO_ERROR); 306adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh while ((file = readdir(dir)) != NULL) { 307adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (!strncmp(name, file->d_name, n)) { 308adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh char *p = &file->d_name[n]; 309adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh params[0].length = decode_key(params[0].value, p, strlen(p)); 310adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh send_message(params[0].value, params[0].length); 311adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 312adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 313adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh closedir(dir); 314adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return -NO_ERROR; 315adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 316adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 317adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t reset() 318adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 319adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh DIR *dir = opendir("."); 320adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh struct dirent *file; 321adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 322adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh memset(&encryption_key, 0, sizeof(encryption_key)); 323adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh memset(&decryption_key, 0, sizeof(decryption_key)); 324adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh state = UNINITIALIZED; 325adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh retry = MAX_RETRY; 326adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 327adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (!dir) { 328adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return SYSTEM_ERROR; 329adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 330adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh while ((file = readdir(dir)) != NULL) { 331c4b144533a9a5d03ee1fbcf27492a8be5737541dChia-chi Yeh unlink(file->d_name); 332adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 333adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh closedir(dir); 334c4b144533a9a5d03ee1fbcf27492a8be5737541dChia-chi Yeh return NO_ERROR; 335adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 336adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 337adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#define MASTER_KEY_FILE ".masterkey" 338adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#define MASTER_KEY_SIZE 16 339adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 340adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic void generate_key(uint8_t *key, uint8_t *password, int length) 341adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 342adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore", 343adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh sizeof("keystore"), 1024, MASTER_KEY_SIZE, key); 344adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 345adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 346adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t password() 347adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 348adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint8_t key[MASTER_KEY_SIZE]; 349adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh AES_KEY aes_key; 350adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int n; 351adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 352adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (state == UNINITIALIZED) { 353adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh blob.length = MASTER_KEY_SIZE; 354adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) { 355adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return SYSTEM_ERROR; 356adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 357adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } else { 358adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh generate_key(key, params[0].value, params[0].length); 359adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key); 360adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh n = decrypt_blob(MASTER_KEY_FILE, &aes_key); 361adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (n == SYSTEM_ERROR) { 362adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return SYSTEM_ERROR; 363adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 364adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) { 365adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (retry <= 0) { 366626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh reset(); 367626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh return UNINITIALIZED; 368adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 369adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return WRONG_PASSWORD + --retry; 370adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 371adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 372adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 373adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (params[1].length == -1) { 374adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh memcpy(key, blob.value, MASTER_KEY_SIZE); 375adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } else { 376adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh generate_key(key, params[1].value, params[1].length); 377adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key); 378adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh memcpy(key, blob.value, MASTER_KEY_SIZE); 379adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh n = encrypt_blob(MASTER_KEY_FILE, &aes_key); 380adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 381adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 382adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (n == NO_ERROR) { 383adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key); 384adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key); 385adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh state = NO_ERROR; 386adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh retry = MAX_RETRY; 387adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 388adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return n; 389adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 390adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 391adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t lock() 392adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 393adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh memset(&encryption_key, 0, sizeof(encryption_key)); 394adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh memset(&decryption_key, 0, sizeof(decryption_key)); 395adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh state = LOCKED; 396c4b144533a9a5d03ee1fbcf27492a8be5737541dChia-chi Yeh return NO_ERROR; 397adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 398adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 399adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t unlock() 400adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 401adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh params[1].length = -1; 402adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return password(); 403adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 404adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 405adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh/* Here are the permissions, actions, users, and the main function. */ 406adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 407adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehenum perm { 408adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh TEST = 1, 409adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh GET = 2, 410adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh INSERT = 4, 411adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh DELETE = 8, 412adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh EXIST = 16, 4131f6802295e2dba50a4549b8a22537dcb4c4dda03Chia-chi Yeh SAW = 32, 414adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh RESET = 64, 415adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh PASSWORD = 128, 416adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh LOCK = 256, 417adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh UNLOCK = 512, 418adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh}; 419adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 420adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic struct action { 421adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int8_t (*run)(); 422adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int8_t code; 423adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int8_t state; 424adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint32_t perm; 425adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int lengths[MAX_PARAM]; 426adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} actions[] = { 427adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {test, 't', 0, TEST, {0}}, 428adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {get, 'g', NO_ERROR, GET, {KEY_SIZE}}, 429adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {insert, 'i', NO_ERROR, INSERT, {KEY_SIZE, VALUE_SIZE}}, 430626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh {delete, 'd', 0, DELETE, {KEY_SIZE}}, 431626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh {exist, 'e', 0, EXIST, {KEY_SIZE}}, 4321f6802295e2dba50a4549b8a22537dcb4c4dda03Chia-chi Yeh {saw, 's', 0, SAW, {KEY_SIZE}}, 433adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {reset, 'r', 0, RESET, {0}}, 434adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {password, 'p', 0, PASSWORD, {PASSWORD_SIZE, PASSWORD_SIZE}}, 435adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {lock, 'l', NO_ERROR, LOCK, {0}}, 436adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {unlock, 'u', LOCKED, UNLOCK, {PASSWORD_SIZE}}, 437adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {NULL, 0 , 0, 0, {0}}, 438adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh}; 439adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 440adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic struct user { 441adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uid_t uid; 442adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uid_t euid; 443adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uint32_t perms; 444adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} users[] = { 4454165dd21592c958bacc97043d56b1ea914ab94c9Chia-chi Yeh {AID_SYSTEM, ~0, ~GET}, 446adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {AID_VPN, AID_SYSTEM, GET}, 447adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh {AID_WIFI, AID_SYSTEM, GET}, 4484165dd21592c958bacc97043d56b1ea914ab94c9Chia-chi Yeh {AID_ROOT, AID_SYSTEM, GET}, 4494165dd21592c958bacc97043d56b1ea914ab94c9Chia-chi Yeh {~0, ~0, TEST | GET | INSERT | DELETE | EXIST | SAW}, 450adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh}; 451adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 452adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehstatic int8_t process(int8_t code) { 453adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh struct user *user = users; 454adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh struct action *action = actions; 455adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int i; 456adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 4574165dd21592c958bacc97043d56b1ea914ab94c9Chia-chi Yeh while (~user->uid && user->uid != uid) { 458adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh ++user; 459adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 460adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh while (action->code && action->code != code) { 461adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh ++action; 462adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 463adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (!action->code) { 464adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return UNDEFINED_ACTION; 465adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 466adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (!(action->perm & user->perms)) { 467adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return PERMISSION_DENIED; 468adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 469adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (action->state && action->state != state) { 470adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return state; 471adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 4724165dd21592c958bacc97043d56b1ea914ab94c9Chia-chi Yeh if (~user->euid) { 473adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uid = user->euid; 474adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 475adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh for (i = 0; i < MAX_PARAM && action->lengths[i]; ++i) { 476adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh params[i].length = recv_message(params[i].value, action->lengths[i]); 477adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (params[i].length == -1) { 478adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return PROTOCOL_ERROR; 479adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 480adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 481626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh if (!recv_end_of_file()) { 482626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh return PROTOCOL_ERROR; 483626c46b016118edbea3a3938425b5d4e959f6f2dChia-chi Yeh } 484adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return action->run(); 485adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 486adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 487adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh#define RANDOM_DEVICE "/dev/urandom" 488adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 489adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yehint main(int argc, char **argv) 490adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh{ 491adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int control_socket = android_get_control_socket("keystore"); 492adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (argc < 2) { 493adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh LOGE("A directory must be specified!"); 494adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return 1; 495adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 496adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (chdir(argv[1]) == -1) { 497adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh LOGE("chdir: %s: %s", argv[1], strerror(errno)); 498adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return 1; 499adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 500adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if ((the_entropy = open(RANDOM_DEVICE, O_RDONLY)) == -1) { 501adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh LOGE("open: %s: %s", RANDOM_DEVICE, strerror(errno)); 502adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return 1; 503adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 504adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (listen(control_socket, 3) == -1) { 505adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh LOGE("listen: %s", strerror(errno)); 506adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return 1; 507adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 508adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 509adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh signal(SIGPIPE, SIG_IGN); 510adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (access(MASTER_KEY_FILE, R_OK) == 0) { 511adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh state = LOCKED; 512adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 513adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 514adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh while ((the_socket = accept(control_socket, NULL, 0)) != -1) { 515adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh struct timeval tv = {.tv_sec = 3}; 516adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh struct ucred cred; 517adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh socklen_t size = sizeof(cred); 518adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int8_t request; 519adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 520adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh setsockopt(the_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); 521adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh setsockopt(the_socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); 522adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 523adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if (getsockopt(the_socket, SOL_SOCKET, SO_PEERCRED, &cred, &size)) { 524adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh LOGW("getsockopt: %s", strerror(errno)); 525adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } else if (recv_code(&request)) { 526adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int8_t old_state = state; 527adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh int8_t response; 528adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh uid = cred.uid; 529adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 530adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh if ((response = process(request)) > 0) { 531adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh send_code(response); 532adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh response = -response; 533adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 534adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh 535adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh LOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d", 536adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh cred.uid, request, -response, old_state, state, retry); 537adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 538adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh close(the_socket); 539adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh } 540adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh LOGE("accept: %s", strerror(errno)); 541adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh return 1; 542adbc99be6d7e35f71bbbdcdfef5562c5a9b53b07Chia-chi Yeh} 543