All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.named_data.jndn.security.identity.AndroidSqlite3IdentityStorage Maven / Gradle / Ivy

Go to download

jNDN is a new implementation of a Named Data Networking client library written in Java. It is wire format compatible with the new NDN-TLV encoding, with NDNx and PARC's CCNx.

There is a newer version: 0.25
Show newest version
/**
 * Copyright (C) 2015-2017 Regents of the University of California.
 * @author: Jeff Thompson 
 * @author: From code in ndn-cxx by Yingdi Yu 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 * A copy of the GNU Lesser General Public License is in the file COPYING.
 */

package net.named_data.jndn.security.identity;

import android.database.sqlite.SQLiteDatabase;
import android.database.Cursor;
import android.content.ContentValues;
import java.io.File;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import net.named_data.jndn.KeyLocator;
import net.named_data.jndn.Name;
import net.named_data.jndn.encoding.EncodingException;
import net.named_data.jndn.security.KeyType;
import net.named_data.jndn.util.Blob;
import net.named_data.jndn.security.SecurityException;
import net.named_data.jndn.security.certificate.IdentityCertificate;

/**
 * AndroidSqlite3IdentityStorage extends IdentityStorage to implement basic
 * storage of identity, public keys and certificates using the
 * android.database.sqlite API.
 */
public class AndroidSqlite3IdentityStorage extends Sqlite3IdentityStorageBase {
  /**
   * Create a new AndroidSqlite3IdentityStorage to use the given full path of
   * the SQLite3 file. This constructor takes the full path instead of just a
   * directory to be more flexible. You can get the default file path from an
   * Android files directory with getDefaultFilePath(context.getFilesDir()).
   * @param databaseFilePath The path of the SQLite file.
   *
   */
  public AndroidSqlite3IdentityStorage(String databaseFilePath)
  {
    construct(databaseFilePath);
  }

  /**
   * Get the default database file path based on the files root. This creates
   * the directory of the default database if it doesn't exist. For example if
   * filesRoot is "/data/data/org.example/files", this returns
   * "/data/data/org.example/files/.ndn/ndnsec-public-info.db".
   * @param filesRoot The root file directory. An Android app can use
   * context.getFilesDir()
   * @return The default file path.
   */
  public static String
  getDefaultFilePath(File filesRoot)
  {
    return getDefaultFilePath(filesRoot.getAbsolutePath());
  }

  /**
   * Get the default database file path based on the files root. This creates
   * the directory of the default database if it doesn't exist.
   * @param filesRoot The root file directory.
   * @return The default file path.
   */
  public static String
  getDefaultFilePath(String filesRoot)
  {
    // NOTE: Use File because java.nio.file.Path is not available before Java 7.
    File identityDir = new File(filesRoot, ".ndn");
    identityDir.mkdirs();
    return new File(identityDir, "ndnsec-public-info.db").getAbsolutePath();
  }

  private void
  construct(String databaseFilePath)
  {
    database_ = SQLiteDatabase.openDatabase
      (databaseFilePath, null,
       SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.CREATE_IF_NECESSARY);

    // Check if the TpmInfo table exists.
    Cursor cursor = database_.rawQuery(SELECT_MASTER_TPM_INFO_TABLE, null);
    boolean tpmInfoTableExists = false;
    if (cursor.moveToNext())
      tpmInfoTableExists = true;
    cursor.close();

    if (!tpmInfoTableExists)
      database_.execSQL(INIT_TPM_INFO_TABLE);

    // Check if the ID table exists.
    cursor = database_.rawQuery(SELECT_MASTER_ID_TABLE, null);
    boolean idTableExists = false;
    if (cursor.moveToNext())
      idTableExists = true;
    cursor.close();

    if (!idTableExists) {
      database_.execSQL(INIT_ID_TABLE1);
      database_.execSQL(INIT_ID_TABLE2);
    }

    // Check if the Key table exists.
    cursor = database_.rawQuery(SELECT_MASTER_KEY_TABLE, null);
    idTableExists = false;
    if (cursor.moveToNext())
      idTableExists = true;
    cursor.close();

    if (!idTableExists) {
      database_.execSQL(INIT_KEY_TABLE1);
      database_.execSQL(INIT_KEY_TABLE2);
    }

    // Check if the Certificate table exists.
    cursor = database_.rawQuery(SELECT_MASTER_CERT_TABLE, null);
    idTableExists = false;
    if (cursor.moveToNext())
      idTableExists = true;
    cursor.close();

    if (!idTableExists) {
      database_.execSQL(INIT_CERT_TABLE1);
      database_.execSQL(INIT_CERT_TABLE2);
      database_.execSQL(INIT_CERT_TABLE3);
    }
  }

  /**
   * Check if the specified identity already exists.
   * @param identityName The identity name.
   * @return True if the identity exists, otherwise false.
   */
  public final boolean
  doesIdentityExist(Name identityName) throws SecurityException
  {
    Cursor cursor = database_.rawQuery
      (SELECT_doesIdentityExist, new String[] { identityName.toUri() });

    try {
      if (cursor.moveToNext())
        return cursor.getInt(0) > 0;
      else
        return false;
    } finally {
      cursor.close();
    }
  }

  /**
   * Add a new identity. Do nothing if the identity already exists.
   * @param identityName The identity name to be added.
   */
  public final void
  addIdentity(Name identityName) throws SecurityException
  {
    if (doesIdentityExist(identityName))
      return;

    ContentValues values = new ContentValues();
    values.put("identity_name", identityName.toUri());
    if (database_.insert("Identity", null, values) < 0)
      throw new SecurityException
        ("AndroidSqlite3IdentityStorage.addIdentity: SQLite error for insert");
  }

  /**
   * Revoke the identity.
   * @return True if the identity was revoked, false if not.
   */
  public final boolean
  revokeIdentity()
  {
    //TODO:
    return false;
  }

  /**
   * Check if the specified key already exists.
   * @param keyName The name of the key.
   * @return true if the key exists, otherwise false.
   */
  public final boolean
  doesKeyExist(Name keyName) throws SecurityException
  {
    String keyId = keyName.get(-1).toEscapedString();
    Name identityName = keyName.getPrefix(-1);

    Cursor cursor = database_.rawQuery
      (SELECT_doesKeyExist, new String[] { identityName.toUri(), keyId });

    try {
      if (cursor.moveToNext())
        return cursor.getInt(0) > 0;
      else
        return false;
    } finally {
      cursor.close();
    }
  }

  /**
   * Add a public key to the identity storage. Also call addIdentity to ensure
   * that the identityName for the key exists. However, if the key already
   * exists, do nothing.
   * @param keyName The name of the public key to be added.
   * @param keyType Type of the public key to be added.
   * @param publicKeyDer A blob of the public key DER to be added.
   */
  public final void
  addKey(Name keyName, KeyType keyType, Blob publicKeyDer) throws SecurityException
  {
    if (keyName.size() == 0)
      return;

    if (doesKeyExist(keyName))
      return;

    String keyId = keyName.get(-1).toEscapedString();
    Name identityName = keyName.getPrefix(-1);

    addIdentity(identityName);

    ContentValues values = new ContentValues();
    values.put("identity_name", identityName.toUri());
    values.put("key_identifier", keyId);
    values.put("key_type", keyType.getNumericType());
    values.put("public_key", publicKeyDer.getImmutableArray());
    if (database_.insert("Key", null, values) < 0)
      throw new SecurityException
          ("AndroidSqlite3IdentityStorage.addKey: SQLite error for insert");
  }

  /**
   * Get the public key DER blob from the identity storage.
   * @param keyName The name of the requested public key.
   * @return The DER Blob.
   * @throws SecurityException if the key doesn't exist.
   */
  public final Blob
  getKey(Name keyName) throws SecurityException
  {
    if (keyName.size() == 0)
      throw new SecurityException
        ("AndroidSqlite3IdentityStorage.getKey: Empty keyName");

    String keyId = keyName.get(-1).toEscapedString();
    Name identityName = keyName.getPrefix(-1);

    Cursor cursor = database_.rawQuery
      (SELECT_getKey, new String[] { identityName.toUri(), keyId });
    try {
      if (cursor.moveToNext())
        return new Blob(cursor.getBlob(0));
      else
        throw new SecurityException
          ("AndroidSqlite3IdentityStorage.getKey: The key does not exist");
    } finally {
      cursor.close();
    }
  }

  /**
   * In table Key, set 'active' to isActive for the keyName.
   * @param keyName The name of the key.
   * @param isActive The value for the 'active' field.
   */
  protected void
  updateKeyStatus(Name keyName, boolean isActive) throws SecurityException
  {
    String keyId = keyName.get(-1).toEscapedString();
    Name identityName = keyName.getPrefix(-1);

    ContentValues values = new ContentValues();
    values.put("active", isActive ? 1 : 0);
    database_.update
      ("Key", values, WHERE_updateKeyStatus,
       new String[] { identityName.toUri(), keyId });
  }

  /**
   * Check if the specified certificate already exists.
   * @param certificateName The name of the certificate.
   * @return True if the certificate exists, otherwise false.
   */
  public final boolean
  doesCertificateExist(Name certificateName) throws SecurityException
  {
    Cursor cursor = database_.rawQuery
      (SELECT_doesCertificateExist, new String[] { certificateName.toUri() });

    try {
      if (cursor.moveToNext())
        return cursor.getInt(0) > 0;
      else
        return false;
    } finally {
      cursor.close();
    }
  }

  /**
   * Add a certificate to the identity storage. Also call addKey to ensure that
   * the certificate key exists. If the certificate is already installed, don't
   * replace it.
   * @param certificate The certificate to be added.  This makes a copy of the
   * certificate.
   */
  public final void
  addCertificate(IdentityCertificate certificate) throws SecurityException
  {
    Name certificateName = certificate.getName();
    Name keyName = certificate.getPublicKeyName();

    addKey(keyName, certificate.getPublicKeyInfo().getKeyType(),
           certificate.getPublicKeyInfo().getKeyDer());

    if (doesCertificateExist(certificateName))
      return;

    // Insert the certificate.
    ContentValues values = new ContentValues();
    values.put("cert_name", certificateName.toUri());
    Name signerName = KeyLocator.getFromSignature
      (certificate.getSignature()).getKeyName();
    values.put("cert_issuer", signerName.toUri());
    String keyId = keyName.get(-1).toEscapedString();
    Name identity = keyName.getPrefix(-1);
    values.put("identity_name", identity.toUri());
    values.put("key_identifier", keyId);
    values.put
      ("not_before",
       dateFormat_.format(new Timestamp((long)certificate.getNotBefore())));
    values.put
      ("not_after",
       dateFormat_.format(new Timestamp((long) certificate.getNotAfter())));
    // wireEncode returns the cached encoding if available.
    values.put("certificate_data", certificate.wireEncode().getImmutableArray());

    if (database_.insert("Certificate", null, values) < 0)
      throw new SecurityException
          ("AndroidSqlite3IdentityStorage.addCertificate: SQLite error for insert");
  }

  /**
   * Get a certificate from the identity storage.
   * @param certificateName The name of the requested certificate.
   * @return The requested certificate.
   * @throws SecurityException if the certificate doesn't exist.
   */
  public final IdentityCertificate
  getCertificate(Name certificateName) throws SecurityException
  {
    if (doesCertificateExist(certificateName)) {
      Cursor cursor = database_.rawQuery
        (SELECT_getCertificate, new String[] { certificateName.toUri() });

      IdentityCertificate certificate = new IdentityCertificate();
      try {
        if (cursor.moveToNext()) {
          try {
            certificate.wireDecode(new Blob(cursor.getBlob(0)));
          } catch (EncodingException ex) {
            throw new SecurityException
              ("AndroidSqlite3IdentityStorage: Error decoding certificate data: " + ex);
          }
        }
        else
          throw new SecurityException
            ("AndroidSqlite3IdentityStorage.getKey: The certificate does not exist");
      } finally {
        cursor.close();
      }

      return certificate;
    }
    else
      return new IdentityCertificate();
  }

  /**
   * Get the TPM locator associated with this storage.
   * @return The TPM locator.
   * @throws SecurityException if the TPM locator doesn't exist.
   */
  public final String
  getTpmLocator() throws SecurityException
  {
    Cursor cursor = database_.rawQuery(SELECT_getTpmLocator, null);

    try {
      if (cursor.moveToNext())
        return cursor.getString(0);
      else
        throw new SecurityException
          ("AndroidSqlite3IdentityStorage.getTpmLocator: TPM info does not exist");
    } finally {
      cursor.close();
    }
  }

  /*****************************************
   *           Get/Set Default             *
   *****************************************/

  /**
   * Get the default identity.
   * @return The name of default identity.
   * @throws SecurityException if the default identity is not set.
   */
  public final Name
  getDefaultIdentity() throws SecurityException
  {
    Cursor cursor = database_.rawQuery(SELECT_getDefaultIdentity, null);

    try {
      if (cursor.moveToNext())
        return new Name(cursor.getString(0));
      else
        throw new SecurityException
          ("AndroidSqlite3IdentityStorage.getDefaultIdentity: The default identity is not defined");
    } finally {
      cursor.close();
    }
  }

  /**
   * Get the default key name for the specified identity.
   * @param identityName The identity name.
   * @return The default key name.
   * @throws SecurityException if the default key name for the identity is not set.
   */
  public final Name
  getDefaultKeyNameForIdentity(Name identityName) throws SecurityException
  {
    Cursor cursor = database_.rawQuery
      (SELECT_getDefaultKeyNameForIdentity,
       new String[] { identityName.toUri() });

    try {
      if (cursor.moveToNext())
        return new Name(identityName).append(cursor.getString(0));
      else
        throw new SecurityException
          ("AndroidSqlite3IdentityStorage.getDefaultKeyNameForIdentity: The default key for the identity is not defined");
    } finally {
      cursor.close();
    }
  }

  /**
   * Get the default certificate name for the specified key.
   * @param keyName The key name.
   * @return The default certificate name.
   * @throws SecurityException if the default certificate name for the key name
   * is not set.
   */
  public final Name
  getDefaultCertificateNameForKey(Name keyName) throws SecurityException
  {
    String keyId = keyName.get(-1).toEscapedString();
    Name identityName = keyName.getPrefix(-1);

    Cursor cursor = database_.rawQuery
      (SELECT_getDefaultCertificateNameForKey,
       new String[] { identityName.toUri(), keyId });

    try {
      if (cursor.moveToNext())
        return new Name(cursor.getString(0));
      else
        throw new SecurityException
          ("AndroidSqlite3IdentityStorage.getDefaultCertificateNameForKey: The default certificate for the key name is not defined");
    } finally {
      cursor.close();
    }
  }

  /**
   * Append all the identity names to the nameList.
   * @param nameList Append result names to nameList.
   * @param isDefault If true, add only the default identity name. If false, add
   * only the non-default identity names.
   */
  public void
  getAllIdentities(ArrayList nameList, boolean isDefault)
    throws SecurityException
  {
    String sql = isDefault ? SELECT_getAllIdentities_default_true
        : SELECT_getAllIdentities_default_false;
    Cursor cursor = database_.rawQuery(sql, new String[0]);

    try {
      while (cursor.moveToNext())
        nameList.add(new Name(cursor.getString(0)));
    } finally {
      cursor.close();
    }
  }

  /**
   * Append all the key names of a particular identity to the nameList.
   * @param identityName The identity name to search for.
   * @param nameList Append result names to nameList.
   * @param isDefault If true, add only the default key name. If false, add only
   * the non-default key names.
   */
  public void
  getAllKeyNamesOfIdentity
    (Name identityName, ArrayList nameList, boolean isDefault) throws SecurityException
  {
    String sql = isDefault ? SELECT_getAllKeyNamesOfIdentity_default_true
      : SELECT_getAllKeyNamesOfIdentity_default_false;
    Cursor cursor = database_.rawQuery(sql, new String[] { identityName.toUri() });

    try {
      while (cursor.moveToNext())
        nameList.add
          (new Name(identityName).append(cursor.getString(0)));
    } finally {
      cursor.close();
    }
  }

  /**
   * Append all the certificate names of a particular key name to the nameList.
   * @param keyName The key name to search for.
   * @param nameList Append result names to nameList.
   * @param isDefault If true, add only the default key name. If false, add only
   * the non-default key names.
   */
  public void
  getAllCertificateNamesOfKey
    (Name keyName, ArrayList nameList, boolean isDefault) throws SecurityException
  {
    String sql = isDefault ? SELECT_getAllCertificateNamesOfKey_default_true
        : SELECT_getAllCertificateNamesOfKey_default_false;
    Cursor cursor = database_.rawQuery
      (sql, new String[] { keyName.getPrefix(-1).toUri(),
                           keyName.get(-1).toEscapedString() });

    try {
      while (cursor.moveToNext())
        nameList.add(new Name(cursor.getString(0)));
    } finally {
      cursor.close();
    }
  }

  /**
   * Set the default identity.  If the identityName does not exist, then clear
   * the default identity so that getDefaultIdentity() throws an exception.
   * @param identityName The default identity name.
   */
  public final void
  setDefaultIdentity(Name identityName) throws SecurityException
  {
    // Reset the previous default identity.
    ContentValues values = new ContentValues();
    values.put("default_identity", 0);
    database_.update
      ("Identity", values, WHERE_setDefaultIdentity_reset, null);

    // Set the current default identity.
    values = new ContentValues();
    values.put("default_identity", 1);
    database_.update
      ("Identity", values, WHERE_setDefaultIdentity_set,
       new String[] { identityName.toUri() });
  }

  /**
   * Set a key as the default key of an identity. The identity name is inferred
   * from keyName.
   * @param keyName The name of the key.
   * @param identityNameCheck The identity name to check that the keyName
   * contains the same identity name. If an empty name, it is ignored.
   */
  public final void
  setDefaultKeyNameForIdentity(Name keyName, Name identityNameCheck)
    throws SecurityException
  {
    checkSetDefaultKeyNameForIdentity(keyName, identityNameCheck);

    String keyId = keyName.get(-1).toEscapedString();
    Name identityName = keyName.getPrefix(-1);

    // Reset the previous default Key.
    ContentValues values = new ContentValues();
    values.put("default_key", 0);
    database_.update
      ("Key", values, WHERE_setDefaultKeyNameForIdentity_reset,
       new String[] { identityName.toUri() });

    // Set the current default Key.
    values = new ContentValues();
    values.put("default_key", 1);
    database_.update
      ("Key", values, WHERE_setDefaultKeyNameForIdentity_set,
       new String[] { identityName.toUri(), keyId });
  }

  /**
   * Set the default key name for the specified identity.
   * @param keyName The key name.
   * @param certificateName The certificate name.
   */
  public final void
  setDefaultCertificateNameForKey(Name keyName, Name certificateName)
    throws SecurityException
  {
    String keyId = keyName.get(-1).toEscapedString();
    Name identityName = keyName.getPrefix(-1);

    // Reset the previous default Certificate.
    ContentValues values = new ContentValues();
    values.put("default_cert", 0);
    database_.update
      ("Certificate", values, WHERE_setDefaultCertificateNameForKey_reset,
       new String[] { identityName.toUri(), keyId });

    // Set the current default Certificate.
    values = new ContentValues();
    values.put("default_cert", 1);
    database_.update
      ("Certificate", values, WHERE_setDefaultCertificateNameForKey_set,
       new String[] { identityName.toUri(), keyId, certificateName.toUri() });
  }

  /*****************************************
   *            Delete Methods             *
   *****************************************/

  /**
   * Delete a certificate.
   * @param certificateName The certificate name.
   */
  public void
  deleteCertificateInfo(Name certificateName) throws SecurityException
  {
    if (certificateName.size() == 0)
      return;

    database_.delete
      ("Certificate", WHERE_deleteCertificateInfo,
       new String[] { certificateName.toUri() });
  }

  /**
   * Delete a public key and related certificates.
   * @param keyName The key name.
   */
  public void
  deletePublicKeyInfo(Name keyName) throws SecurityException
  {
    if (keyName.size() == 0)
      return;

    String keyId = keyName.get(-1).toEscapedString();
    Name identityName = keyName.getPrefix(-1);

    database_.delete
      ("Certificate", WHERE_deletePublicKeyInfo,
       new String[] { identityName.toUri(), keyId });
    database_.delete
      ("Key", WHERE_deletePublicKeyInfo,
       new String[] { identityName.toUri(), keyId });
  }

  /**
   * Delete an identity and related public keys and certificates.
   * @param identityName The identity name.
   */
  public void
  deleteIdentityInfo(Name identityName) throws SecurityException
  {
    String identity = identityName.toUri();

    database_.delete
      ("Certificate", WHERE_deleteIdentityInfo, new String[] { identity });
    database_.delete
      ("Key", WHERE_deleteIdentityInfo, new String[] { identity });
    database_.delete
      ("Identity", WHERE_deleteIdentityInfo, new String[] { identity });
  }

  private SQLiteDatabase database_;
  private static final SimpleDateFormat dateFormat_ =
    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy