diff options
-rw-r--r-- | cmds/keystore/keymgmt.c | 32 | ||||
-rw-r--r-- | core/java/android/app/SuggestionsAdapter.java | 22 | ||||
-rw-r--r-- | core/java/android/text/format/DateFormat.java | 34 | ||||
-rw-r--r-- | core/java/android/widget/DatePicker.java | 77 | ||||
-rw-r--r-- | keystore/java/android/security/CertTool.java | 4 | ||||
-rw-r--r-- | keystore/jni/cert.c | 56 | ||||
-rw-r--r-- | keystore/jni/cert.h | 5 |
7 files changed, 148 insertions, 82 deletions
diff --git a/cmds/keystore/keymgmt.c b/cmds/keystore/keymgmt.c index 66edd56..c45b53c 100644 --- a/cmds/keystore/keymgmt.c +++ b/cmds/keystore/keymgmt.c @@ -79,14 +79,26 @@ static int encrypt_n_save(AES_KEY *enc_key, DATA_BLOB *blob, { int size, fd, ret = -1; unsigned char enc_blob[MAX_BLOB_LEN]; - char tmpfile[KEYFILE_LEN]; + + if ((keyfile == NULL) || (strlen(keyfile) >= (KEYFILE_LEN - 4))) { + LOGE("keyfile name is too long or null"); + return -1; + } strcpy(tmpfile, keyfile); strcat(tmpfile, ".tmp"); // prepare the blob + if (IV_LEN > USER_KEY_LEN) { + LOGE("iv length is too long."); + return -1; + } memcpy(blob->iv, iv, IV_LEN); blob->blob_size = get_blob_size(blob); + if (blob->blob_size > MAX_BLOB_LEN) { + LOGE("blob data size is too large."); + return -1; + } memcpy(enc_blob, blob->blob, blob->blob_size); AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob, blob->blob_size, enc_key, iv, AES_ENCRYPT); @@ -133,8 +145,13 @@ static int store_master_key(char *upasswd, unsigned char *master_key) DATA_BLOB blob; // prepare the blob + if (strlen(MASTER_KEY_TAG) >= USER_KEY_LEN) return -1; strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN); blob.value_size = USER_KEY_LEN; + if (USER_KEY_LEN > MAX_KEY_VALUE_LENGTH) { + LOGE("master_key length is too long."); + return -1; + } memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN); // generate the encryption key @@ -150,6 +167,10 @@ static int get_master_key(char *upasswd, unsigned char *master_key) get_decrypt_key(upasswd, &key); ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob); + if (blob.value_size > USER_KEY_LEN) { + LOGE("the blob's value size is too large"); + return -1; + } if (!ret) memcpy(master_key, blob.value, blob.value_size); return ret; } @@ -224,8 +245,16 @@ int put_key(const char *namespace, const char *keyname, } sprintf(keyfile, KEYFILE_NAME, namespace, keyname); // flatten the args + if (strlen(keyname) >= MAX_KEY_NAME_LENGTH) { + LOGE("keyname is too long."); + return -1; + } strcpy(blob.keyname, keyname); blob.value_size = size; + if (size > MAX_KEY_VALUE_LENGTH) { + LOGE("the data size is too large."); + return -1; + } memcpy(blob.value, data, size); return encrypt_n_save(&encryptKey, &blob, keyfile); } @@ -246,6 +275,7 @@ int get_key(const char *namespace, const char *keyname, ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob); if (!ret) { if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) { + LOGE("blob value size is too large."); ret = -1; } else { *size = blob.value_size; diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java index 54061ae..17e6e50 100644 --- a/core/java/android/app/SuggestionsAdapter.java +++ b/core/java/android/app/SuggestionsAdapter.java @@ -136,6 +136,8 @@ class SuggestionsAdapter extends ResourceCursorAdapter { private int mPreviousLength = 0; public long getPostingDelay(CharSequence constraint) { + if (constraint == null) return 0; + long delay = constraint.length() < mPreviousLength ? DELETE_KEY_POST_DELAY : 0; mPreviousLength = constraint.length(); return delay; @@ -196,14 +198,18 @@ class SuggestionsAdapter extends ResourceCursorAdapter { callCursorPreClose(mCursor); } - super.changeCursor(c); - if (c != null) { - mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT); - mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1); - mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2); - mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1); - mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2); - mBackgroundColorCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR); + try { + super.changeCursor(c); + if (c != null) { + mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT); + mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1); + mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2); + mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1); + mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2); + mBackgroundColorCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR); + } + } catch (Exception e) { + Log.e(LOG_TAG, "error changing cursor and caching columns", e); } } diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index 3d10f17..524f941 100644 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -284,6 +284,12 @@ public class DateFormat { */ public static java.text.DateFormat getDateFormatForSetting(Context context, String value) { + String format = getDateFormatStringForSetting(context, value); + + return new java.text.SimpleDateFormat(format); + } + + private static String getDateFormatStringForSetting(Context context, String value) { if (value != null) { int month = value.indexOf('M'); int day = value.indexOf('d'); @@ -291,7 +297,7 @@ public class DateFormat { if (month >= 0 && day >= 0 && year >= 0) { String template = context.getString(R.string.numeric_date_template); - if (year < month) { + if (year < month && year < day) { if (month < day) { value = String.format(template, "yyyy", "MM", "dd"); } else { @@ -311,7 +317,7 @@ public class DateFormat { } } - return new java.text.SimpleDateFormat(value); + return value; } } @@ -321,7 +327,7 @@ public class DateFormat { * so that we get a four-digit year instead a two-digit year. */ value = context.getString(R.string.numeric_date_format); - return new java.text.SimpleDateFormat(value); + return value; } /** @@ -347,7 +353,11 @@ public class DateFormat { /** * Gets the current date format stored as a char array. The array will contain * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order - * preferred by the user. + * specified by the user's format preference. Note that this order is + * only appropriate for all-numeric dates; spelled-out (MEDIUM and LONG) + * dates will generally contain other punctuation, spaces, or words, + * not just the day, month, and year, and not necessarily in the same + * order returned here. */ public static final char[] getDateFormatOrder(Context context) { char[] order = new char[] {DATE, MONTH, YEAR}; @@ -380,22 +390,10 @@ public class DateFormat { } private static String getDateFormatString(Context context) { - java.text.DateFormat df; - df = java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT); - if (df instanceof SimpleDateFormat) { - return ((SimpleDateFormat) df).toPattern(); - } - String value = Settings.System.getString(context.getContentResolver(), Settings.System.DATE_FORMAT); - if (value == null || value.length() < 6) { - /* - * No need to localize -- this is an emergency fallback in case - * the setting is missing, but it should always be set. - */ - value = "MM-dd-yyyy"; - } - return value; + + return getDateFormatStringForSetting(context, value); } /** diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 3b9f1de..5e76cc3 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -31,6 +31,7 @@ import com.android.internal.widget.NumberPicker; import com.android.internal.widget.NumberPicker.OnChangedListener; import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; import java.util.Calendar; /** @@ -101,7 +102,8 @@ public class DatePicker extends FrameLayout { mMonthPicker = (NumberPicker) findViewById(R.id.month); mMonthPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); DateFormatSymbols dfs = new DateFormatSymbols(); - mMonthPicker.setRange(1, 12, dfs.getShortMonths()); + String[] months = dfs.getShortMonths(); + mMonthPicker.setRange(1, 12, months); mMonthPicker.setSpeed(200); mMonthPicker.setOnChangeListener(new OnChangedListener() { public void onChanged(NumberPicker picker, int oldVal, int newVal) { @@ -146,7 +148,7 @@ public class DatePicker extends FrameLayout { init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), null); // re-order the number pickers to match the current date format - reorderPickers(); + reorderPickers(months); if (!isEnabled()) { setEnabled(false); @@ -161,30 +163,70 @@ public class DatePicker extends FrameLayout { mYearPicker.setEnabled(enabled); } - private void reorderPickers() { - char[] order = DateFormat.getDateFormatOrder(mContext); - - /* Default order is month, date, year so if that's the order then - * do nothing. + private void reorderPickers(String[] months) { + java.text.DateFormat format; + String order; + + /* + * If the user is in a locale where the medium date format is + * still numeric (Japanese and Czech, for example), respect + * the date format order setting. Otherwise, use the order + * that the locale says is appropriate for a spelled-out date. */ - if ((order[0] == DateFormat.MONTH) && (order[1] == DateFormat.DATE)) { - return; + + if (months[0].startsWith("1")) { + format = DateFormat.getDateFormat(getContext()); + } else { + format = DateFormat.getMediumDateFormat(getContext()); } - + + if (format instanceof SimpleDateFormat) { + order = ((SimpleDateFormat) format).toPattern(); + } else { + // Shouldn't happen, but just in case. + order = new String(DateFormat.getDateFormatOrder(getContext())); + } + /* Remove the 3 pickers from their parent and then add them back in the * required order. */ LinearLayout parent = (LinearLayout) findViewById(R.id.parent); parent.removeAllViews(); - for (char c : order) { - if (c == DateFormat.DATE) { - parent.addView(mDayPicker); - } else if (c == DateFormat.MONTH) { - parent.addView(mMonthPicker); - } else { - parent.addView (mYearPicker); + + boolean quoted = false; + boolean didDay = false, didMonth = false, didYear = false; + + for (int i = 0; i < order.length(); i++) { + char c = order.charAt(i); + + if (c == '\'') { + quoted = !quoted; + } + + if (!quoted) { + if (c == DateFormat.DATE && !didDay) { + parent.addView(mDayPicker); + didDay = true; + } else if ((c == DateFormat.MONTH || c == 'L') && !didMonth) { + parent.addView(mMonthPicker); + didMonth = true; + } else if (c == DateFormat.YEAR && !didYear) { + parent.addView (mYearPicker); + didYear = true; + } } } + + // Shouldn't happen, but just in case. + if (!didMonth) { + parent.addView(mMonthPicker); + } + if (!didDay) { + parent.addView(mDayPicker); + } + if (!didYear) { + parent.addView(mYearPicker); + } } public void updateDate(int year, int monthOfYear, int dayOfMonth) { @@ -192,6 +234,7 @@ public class DatePicker extends FrameLayout { mMonth = monthOfYear; mDay = dayOfMonth; updateSpinners(); + reorderPickers(new DateFormatSymbols().getShortMonths()); } private static class SavedState extends BaseSavedState { diff --git a/keystore/java/android/security/CertTool.java b/keystore/java/android/security/CertTool.java index 79418bd..1de007d 100644 --- a/keystore/java/android/security/CertTool.java +++ b/keystore/java/android/security/CertTool.java @@ -72,7 +72,7 @@ public class CertTool { private native String getPkcs12PrivateKey(int handle); private native String popPkcs12CertificateStack(int handle); private native void freePkcs12Handle(int handle); - private native String generateCertificateRequest(int bits, String subject); + private native String generateCertificateRequest(int bits, String challenge); private native boolean isPkcs12Keystore(byte[] data); private native int generateX509Certificate(byte[] data); private native boolean isCaCertificate(int handle); @@ -124,7 +124,7 @@ public class CertTool { public String generateKeyPair(int keyStrengthIndex, String challenge, String dirName) { return generateCertificateRequest(getKeyLength(keyStrengthIndex), - dirName); + challenge); } private Intent prepareIntent(String title, byte[] data, String namespace, diff --git a/keystore/jni/cert.c b/keystore/jni/cert.c index 0db28fd..ea21b7d 100644 --- a/keystore/jni/cert.c +++ b/keystore/jni/cert.c @@ -36,17 +36,17 @@ static char emsg[][30] = { STR(ERR_CONSTRUCT_NEW_DATA), STR(ERR_RSA_KEYGEN), STR(ERR_X509_PROCESS), - STR(ERR_BIO_READ), + STR(ERR_SPKAC_TOO_LONG), + STR(ERR_INVALID_ARGS), }; -static void save_in_store(X509_REQ *req, EVP_PKEY *pkey) +static void save_in_store(EVP_PKEY *pkey) { EVP_PKEY *newpkey = EVP_PKEY_new(); RSA *rsa = EVP_PKEY_get1_RSA(pkey); EVP_PKEY_set1_RSA(newpkey, rsa); PKEY_STORE_free(pkey_store[store_index]); - pkey_store[store_index].key_len = - i2d_X509_PUBKEY(req->req_info->pubkey, &pkey_store[store_index].public_key); + pkey_store[store_index].key_len = i2d_RSAPublicKey(rsa, &pkey_store[store_index].public_key); pkey_store[store_index++].pkey = newpkey; store_index %= KEYGEN_STORE_SIZE; RSA_free(rsa); @@ -69,17 +69,19 @@ static EVP_PKEY *get_pkey_from_store(X509 *cert) return (i == KEYGEN_STORE_SIZE) ? NULL : pkey_store[i].pkey; } -int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX]) +int gen_csr(int bits, const char *challenge, char reply[REPLY_MAX]) { int len, ret_code = 0; BIGNUM *bn = NULL; - BIO *bio = NULL; + char *spkstr = NULL; EVP_PKEY *pkey = NULL; RSA *rsa = NULL; - X509_REQ *req = NULL; - X509_NAME *name = NULL; + NETSCAPE_SPKI *req = NULL; - if ((bio = BIO_new(BIO_s_mem())) == NULL) goto err; + if (challenge == NULL) { + ret_code = ERR_INVALID_ARGS; + goto err; + } if ((bits != KEYLENGTH_MEDIUM) && (bits != KEYLENGTH_MAXIMUM)) { ret_code = ERR_INVALID_KEY_LENGTH; @@ -87,7 +89,7 @@ int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX]) } if (((pkey = EVP_PKEY_new()) == NULL) || - ((req = X509_REQ_new()) == NULL) || + ((req = NETSCAPE_SPKI_new()) == NULL) || ((rsa = RSA_new()) == NULL) || ((bn = BN_new()) == NULL)) { ret_code = ERR_CONSTRUCT_NEW_DATA; goto err; @@ -100,40 +102,26 @@ int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX]) goto err; } - // rsa will be part of the req, it will be freed in X509_REQ_free(req) rsa = NULL; + ASN1_STRING_set(req->spkac->challenge, challenge, (int)strlen(challenge)); + NETSCAPE_SPKI_set_pubkey(req, pkey); + NETSCAPE_SPKI_sign(req, pkey, EVP_md5()); + spkstr = NETSCAPE_SPKI_b64_encode(req); - X509_REQ_set_pubkey(req, pkey); - name = X509_REQ_get_subject_name(req); - - X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, - (const unsigned char *)"US", -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, - (const unsigned char *) ANDROID_KEYSTORE, - -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, - (const unsigned char *)organizations, -1, -1, 0); - - if (!X509_REQ_sign(req, pkey, EVP_md5()) || - (PEM_write_bio_X509_REQ(bio, req) <= 0)) { - ret_code = ERR_X509_PROCESS; - goto err; - } - if ((len = BIO_read(bio, reply, REPLY_MAX - 1)) > 0) { - reply[len] = 0; - save_in_store(req, pkey); + if ((strlcpy(reply, spkstr, REPLY_MAX)) < REPLY_MAX) { + save_in_store(pkey); } else { - ret_code = ERR_BIO_READ; + ret_code = ERR_SPKAC_TOO_LONG; } err: if (rsa) RSA_free(rsa); if (bn) BN_free(bn); - if (req) X509_REQ_free(req); + if (req) NETSCAPE_SPKI_free(req); if (pkey) EVP_PKEY_free(pkey); - if (bio) BIO_free(bio); + if (spkstr) OPENSSL_free(spkstr); if ((ret_code > 0) && (ret_code < ERR_MAXIMUM)) LOGE(emsg[ret_code]); - return ret_code; + return -ret_code; } PKCS12 *get_p12_handle(const char *buf, int bufLen) diff --git a/keystore/jni/cert.h b/keystore/jni/cert.h index aaa7602..a9e1a9e 100644 --- a/keystore/jni/cert.h +++ b/keystore/jni/cert.h @@ -32,8 +32,9 @@ #define ERR_CONSTRUCT_NEW_DATA 2 #define ERR_RSA_KEYGEN 3 #define ERR_X509_PROCESS 4 -#define ERR_BIO_READ 5 -#define ERR_MAXIMUM 6 +#define ERR_SPKAC_TOO_LONG 5 +#define ERR_INVALID_ARGS 6 +#define ERR_MAXIMUM 7 typedef struct { EVP_PKEY *pkey; |