A key directory holds a key (secret or private), distributed to entities (represented by public keys), by a set of key blocks each of which wrapping that key under different target keys. More...
Classes | |
class | NoPrivateKeyException |
Public Member Functions | |
KeyDirectory (ContentName directoryName, CCNHandle handle) throws IOException | |
Directory name should be versioned, else we pull the latest version; start enumeration. | |
KeyDirectory (ContentName directoryName, boolean enumerate, CCNHandle handle) throws IOException | |
Directory name should be versioned, else we pull the latest version. | |
boolean | hasResult () |
Subclasses should override this test to answer true if waiters should break out of a waitForNoUpdatesOrResult loop. | |
TreeSet< byte[]> | getCopyOfWrappingKeyIDs () throws ContentNotReadyException |
Return a copy to avoid synchronization problems. | |
TreeSet< byte[]> | getCopyOfOtherNames () throws ContentNotReadyException |
Returns a copy to avoid synchronization problems. | |
WrappedKeyObject | getWrappedKeyForKeyID (byte[] keyID) throws ContentDecodingException, IOException |
Returns the wrapped key object corresponding to a public key specified by its digest. | |
ContentName | getWrappedKeyNameForKeyID (byte[] keyID) |
Returns the wrapped key name for a public key specified by its digest. | |
boolean | hasSupersededBlock () throws ContentNotReadyException |
Checks for the existence of a superseded block. | |
ContentName | getSupersededBlockName () |
WrappedKeyObject | getSupersededWrappedKey () throws ContentDecodingException, ContentNotReadyException, IOException |
We have several choices for how to represent superseded and previous keys. | |
WrappedKeyObject | getWrappedKey (ContentName wrappedKeyName) throws ContentDecodingException, IOException |
Returns the wrapped key object corresponding to the specified wrapped key name. | |
boolean | hasPreviousKeyBlock () throws ContentNotReadyException |
Checks for the existence of a previous key block. | |
ContentName | getPreviousKeyBlockName () |
Link | getPreviousKey (long timeout) throws ContentNotReadyException, IOException |
Returns a link to the previous key. | |
boolean | hasPrivateKeyBlock () throws ContentNotReadyException |
We store a private key as a single block wrapped under a nonce key, which is then wrapped under the public keys of various principals. | |
ContentName | getPrivateKeyBlockName () |
Key | getUnwrappedKey (byte[] expectedKeyID) throws InvalidKeyException, ContentDecodingException, IOException, NoSuchAlgorithmException |
Unwrap and return the key wrapped in a wrapping key specified by its digest. | |
boolean | isPrivateKeyInCache () |
PrivateKey | getPrivateKey () throws AccessDeniedException, InvalidKeyException, ContentNotReadyException, ContentGoneException, ContentDecodingException, IOException, NoSuchAlgorithmException |
Returns the private key stored in the KeyDirectory. | |
WrappedKeyObject | addWrappedKeyBlock (Key secretKeyToWrap, ContentName publicKeyName, PublicKey publicKey) throws ContentEncodingException, IOException, InvalidKeyException, VersionMissingException |
Writes a wrapped key block to the repository. | |
void | addPrivateKeyBlock (PrivateKey privateKey, Key privateKeyWrappingKey) throws ContentEncodingException, IOException, InvalidKeyException |
Writes a private key block to the repository. | |
void | addSupersededByBlock (Key oldPrivateKeyWrappingKey, ContentName storedSupersedingKeyName, byte[] storedSupersedingKeyID, Key newPrivateKeyWrappingKey) throws InvalidKeyException, ContentEncodingException, IOException |
Add a superseded-by block to our key directory. | |
void | addPreviousKeyLink (ContentName previousKey, PublisherID previousKeyPublisher) throws ContentEncodingException, IOException |
Writes a link to a previous key to the repository. | |
void | addPreviousKeyBlock (Key oldPrivateKeyWrappingKey, ContentName supersedingKeyName, Key newPrivateKeyWrappingKey) throws InvalidKeyException, ContentEncodingException, IOException |
Writes a previous key block to the repository. | |
Static Public Member Functions | |
static ContentName | getSupersededBlockNameForKey (ContentName versionedKeyName) |
static ContentName | getPreviousKeyBlockName (ContentName keyDirectoryName) |
static void | addSupersededByBlock (ContentName oldKeyVersionedNameToAddBlockTo, Key oldKeyToBeSuperseded, ContentName storedSupersedingKeyName, byte[] storedSupersedingKeyID, Key supersedingKey, CCNHandle handle) throws ContentEncodingException, IOException, InvalidKeyException |
Add a superseded-by block to another node key, where we may have only its name, not its enumeration. | |
Static Public Attributes | |
static final byte[] | SUPERSEDED_MARKER = "SupersededBy".getBytes() |
static final byte[] | PREVIOUS_KEY_NAME = "PreviousKey".getBytes() |
static final byte[] | GROUP_PUBLIC_KEY_NAME = "Key".getBytes() |
static final byte[] | GROUP_PRIVATE_KEY_NAME = "PrivateKey".getBytes() |
Protected Member Functions | |
void | initialize (boolean startEnumerating) throws IOException |
We don't start enumerating until we get here. | |
void | processNewChildren (SortedSet< ContentName > newChildren) |
Called each time new data comes in, gets to parse it and load processed arrays. | |
void | processNewChild (byte[] wkChildName) |
WrappedKeyObject | getPrivateKeyObject () throws ContentGoneException, IOException |
Returns the private key object, if one exists as a wrapped key object. | |
Key | findUnwrappedKey (byte[] expectedKeyID) throws IOException, ContentNotReadyException, InvalidKeyException, ContentDecodingException, NoSuchAlgorithmException |
Key | unwrapKeyViaCache (byte[] keyIDOfCachedKeytoUse) throws ContentDecodingException, IOException, InvalidKeyException, NoSuchAlgorithmException |
Fast path -- once we have an idea which of our keys will unwrap this key, get it. | |
Key | unwrapKeyViaCache () throws InvalidKeyException, ContentDecodingException, IOException, NoSuchAlgorithmException |
Key | unwrapKeyViaSupersededKey () throws InvalidKeyException, ContentDecodingException, IOException, NoSuchAlgorithmException |
KeyDirectory | factory (ContentName name) throws IOException |
Protected Attributes | |
CCNHandle | _handle |
boolean | cacheHit |
Static Protected Attributes | |
static final Comparator< byte[]> | byteArrayComparator = new ByteArrayCompare() |
Package Attributes | |
TreeSet< byte[]> | _keyIDs = new TreeSet<byte []>(byteArrayComparator) |
The set _keyIDs contains the digests of the (public) wrapping keys of the wrapped key objects stored in the KeyDirectory. | |
final ReadWriteLock | _keyIDLock = new ReentrantReadWriteLock() |
TreeSet< byte[]> | _otherNames = new TreeSet<byte []>(byteArrayComparator) |
The set _otherNames records the presence of superseded keys, previous keys, group private keys, etc. | |
final ReadWriteLock | _otherNamesLock = new ReentrantReadWriteLock() |
A key directory holds a key (secret or private), distributed to entities (represented by public keys), by a set of key blocks each of which wrapping that key under different target keys.
If the key to be distributed is a private key, it is first wrapped under a nonce key, and that nonce key is stored encrypted under the keys of the receiving entitites.
Essentially a KeyDirectory is a software wrapper for managing a set of content stored in CCNx (writing and reading portions of that content); that content consists of a set of key blocks used to give one key to a number of target entities.
Key blocks are implemented as a set of wrapped key objects all stored in one directory. Wrapped key objects are typically short and only need one segment. The directory the keys are stored in is prefixed by a version, to allow the contents to evolve. In addition some potential supporting information pointing to previous or subsequent versions of this key is kept. A particular wrapped key entry's name would look like:
<keyname>/version/xxx/s0
Where xxx is the identifier of the wrapped key.
Our model is that higher-level function may use this interface to try many ways to get a given key. Some will work (access is allowed), some may not -- the latter does not mean that the principal doesn't have access, just that the principal doesn't have access by this route. So for the moment, we return null when we don't conclusively know that this principal doesn't have access to this data somehow, rather than throwing AccessDeniedException.
org.ccnx.ccn.io.content.KeyDirectory.KeyDirectory | ( | ContentName | directoryName, | |
CCNHandle | handle | |||
) | throws IOException |
Directory name should be versioned, else we pull the latest version; start enumeration.
manager | the access control manager. | |
directoryName | the root of the KeyDirectory. | |
handle |
IOException |
org.ccnx.ccn.io.content.KeyDirectory.KeyDirectory | ( | ContentName | directoryName, | |
boolean | enumerate, | |||
CCNHandle | handle | |||
) | throws IOException |
Directory name should be versioned, else we pull the latest version.
directoryName | the root of the KeyDirectory. | |
handle |
IOException |
void org.ccnx.ccn.io.content.KeyDirectory.addPreviousKeyBlock | ( | Key | oldPrivateKeyWrappingKey, | |
ContentName | supersedingKeyName, | |||
Key | newPrivateKeyWrappingKey | |||
) | throws InvalidKeyException, ContentEncodingException, IOException |
Writes a previous key block to the repository.
oldPrivateKeyWrappingKey | ||
supersedingKeyName | ||
newPrivateKeyWrappingKey |
InvalidKeyException | ||
ContentEncodingException | ||
IOException |
void org.ccnx.ccn.io.content.KeyDirectory.addPreviousKeyLink | ( | ContentName | previousKey, | |
PublisherID | previousKeyPublisher | |||
) | throws ContentEncodingException, IOException |
Writes a link to a previous key to the repository.
previousKey | ||
previousKeyPublisher |
ContentEncodingException | ||
IOException |
void org.ccnx.ccn.io.content.KeyDirectory.addPrivateKeyBlock | ( | PrivateKey | privateKey, | |
Key | privateKeyWrappingKey | |||
) | throws ContentEncodingException, IOException, InvalidKeyException |
Writes a private key block to the repository.
privateKey | the private key. | |
privateKeyWrappingKey | the wrapping key used to wrap the private key. |
ContentEncodingException | ||
IOException | ||
InvalidKeyException |
static void org.ccnx.ccn.io.content.KeyDirectory.addSupersededByBlock | ( | ContentName | oldKeyVersionedNameToAddBlockTo, | |
Key | oldKeyToBeSuperseded, | |||
ContentName | storedSupersedingKeyName, | |||
byte[] | storedSupersedingKeyID, | |||
Key | supersedingKey, | |||
CCNHandle | handle | |||
) | throws ContentEncodingException, IOException, InvalidKeyException [static] |
Add a superseded-by block to another node key, where we may have only its name, not its enumeration.
Use as a static method to add our own superseded-by blocks as well.
ContentEncodingException | ||
IOException | ||
InvalidKeyException |
void org.ccnx.ccn.io.content.KeyDirectory.addSupersededByBlock | ( | Key | oldPrivateKeyWrappingKey, | |
ContentName | storedSupersedingKeyName, | |||
byte[] | storedSupersedingKeyID, | |||
Key | newPrivateKeyWrappingKey | |||
) | throws InvalidKeyException, ContentEncodingException, IOException |
Add a superseded-by block to our key directory.
oldPrivateKeyWrappingKey | ||
supersedingKeyName | ||
newPrivateKeyWrappingKey |
ContentEncodingException | ||
IOException | ||
InvalidKeyException |
WrappedKeyObject org.ccnx.ccn.io.content.KeyDirectory.addWrappedKeyBlock | ( | Key | secretKeyToWrap, | |
ContentName | publicKeyName, | |||
PublicKey | publicKey | |||
) | throws ContentEncodingException, IOException, InvalidKeyException, VersionMissingException |
Writes a wrapped key block to the repository.
Eventually aggregate signing and repo stream operations at the very least across writing paired objects and links, preferably across larger swaths of data.
secretKeyToWrap | either a node key, a data key, or a private key wrapping key | |
publicKeyName | the name of the public key. | |
publicKey | the public key. |
ContentEncodingException | ||
IOException | ||
InvalidKeyException | ||
VersionMissingException | ||
VersionMissingException |
Reimplemented in org.ccnx.ccn.profiles.security.access.group.PrincipalKeyDirectory.
TreeSet<byte []> org.ccnx.ccn.io.content.KeyDirectory.getCopyOfOtherNames | ( | ) | throws ContentNotReadyException |
Returns a copy to avoid synchronization problems.
ContentNotReadyException |
TreeSet<byte []> org.ccnx.ccn.io.content.KeyDirectory.getCopyOfWrappingKeyIDs | ( | ) | throws ContentNotReadyException |
Return a copy to avoid synchronization problems.
ContentNotReadyException |
Link org.ccnx.ccn.io.content.KeyDirectory.getPreviousKey | ( | long | timeout | ) | throws ContentNotReadyException, IOException |
Returns a link to the previous key.
Previous key might be a link, if we're a simple newer version, or it might be a wrapped key, if we're an interposed node key. DKS TODO
IOException | ||
ContentNotReadyException | ||
ContentDecodingException |
PrivateKey org.ccnx.ccn.io.content.KeyDirectory.getPrivateKey | ( | ) | throws AccessDeniedException, InvalidKeyException, ContentNotReadyException, ContentGoneException, ContentDecodingException, IOException, NoSuchAlgorithmException |
Returns the private key stored in the KeyDirectory.
The private key is wrapped in a wrapping key, which is itself wrapped. So the unwrapping proceeds in two steps. First, we unwrap the wrapping key for the private key. Then, we unwrap the private key itself. Relies on the caller, who presumably knows the public key, to add the result to the cache.
AccessDeniedException | ||
ContentGoneException | ||
ContentNotReadyException | ||
InvalidKeyException | ||
ContentDecodingException | ||
IOException | ||
NoSuchAlgorithmException |
WrappedKeyObject org.ccnx.ccn.io.content.KeyDirectory.getPrivateKeyObject | ( | ) | throws ContentGoneException, IOException [protected] |
Returns the private key object, if one exists as a wrapped key object.
Does not check to see if we have a private key block; simply sends a request for it (saves the requirement to do enumeration). Callers should check available() on the result to see if we actually got one. In general, callers will know whether one should exist or not. hasPrivateKeyBlock can be used to test (after enumeration) whether one exists if you don't know.
IOException | ||
ContentGoneException | ||
ContentDecodingException |
WrappedKeyObject org.ccnx.ccn.io.content.KeyDirectory.getSupersededWrappedKey | ( | ) | throws ContentDecodingException, ContentNotReadyException, IOException |
We have several choices for how to represent superseded and previous keys.
Ignoring for now the case where we might have to have more than one per key directory (e.g. if we represent removal of several interposed ACLs), we could have the wrapped key block stored in the superseded block location, and the previous key block be a link, or the previous key block be a wrapped key and the superseded location be a link. Or we could store wrapped key blocks in both places. Because the wrapped key blocks can contain the name of the key that wrapped them (but not the key being wrapped), they are in essence a pointer forward to the replacing key. So, the superseded block, if it contains a wrapped key, is both a key and a link. If the block was stored at the previous key, it would not be both a key and a link, as its wrapping key is indicated by where it is. So it should indeed be a link -- except in the case of an interposed ACL, where there is nothing to link to; and it instead stores a wrapped key block containing the effective node key that was the previous key. This method checks for the existence of a superseded block.
ContentNotReadyException | ||
ContentDecodingException | ||
IOException |
Key org.ccnx.ccn.io.content.KeyDirectory.getUnwrappedKey | ( | byte[] | expectedKeyID | ) | throws InvalidKeyException, ContentDecodingException, IOException, NoSuchAlgorithmException |
Unwrap and return the key wrapped in a wrapping key specified by its digest.
Find a copy of the key block in this directory that we can unwrap (either the private key wrapping key block or a wrapped raw symmetric key). Chase superseding keys if we have to. This mechanism should be generic, and should work for node keys as well as private key wrapping keys in directories following this structure.
InvalidKeyException | ||
ContentDecodingException | ||
IOException | ||
NoSuchAlgorithmException |
WrappedKeyObject org.ccnx.ccn.io.content.KeyDirectory.getWrappedKey | ( | ContentName | wrappedKeyName | ) | throws ContentDecodingException, IOException |
Returns the wrapped key object corresponding to the specified wrapped key name.
We know there is only one version of this object, so avoid getLatestVersion.
wrappedKeyName |
IOException | ||
ContentDecodingException |
WrappedKeyObject org.ccnx.ccn.io.content.KeyDirectory.getWrappedKeyForKeyID | ( | byte[] | keyID | ) | throws ContentDecodingException, IOException |
Returns the wrapped key object corresponding to a public key specified by its digest.
Up to caller to decide when this is reasonable to call; should call available() on result.
keyID | the digest of the specified public key. |
ContentDecodingException | ||
IOException |
ContentName org.ccnx.ccn.io.content.KeyDirectory.getWrappedKeyNameForKeyID | ( | byte[] | keyID | ) |
Returns the wrapped key name for a public key specified by its digest.
keyID | the digest of the public key. |
boolean org.ccnx.ccn.io.content.KeyDirectory.hasPreviousKeyBlock | ( | ) | throws ContentNotReadyException |
Checks for the existence of a previous key block.
ContentNotReadyException |
boolean org.ccnx.ccn.io.content.KeyDirectory.hasPrivateKeyBlock | ( | ) | throws ContentNotReadyException |
We store a private key as a single block wrapped under a nonce key, which is then wrapped under the public keys of various principals.
The WrappedKey structure would allow us to do this (wrap private in public) in a single object, with an inline nonce key, but this option is more efficient. Checks for the existence of a private key block
ContentNotReadyException |
boolean org.ccnx.ccn.io.content.KeyDirectory.hasResult | ( | ) |
Subclasses should override this test to answer true if waiters should break out of a waitForNoUpdatesOrResult loop.
Note that results must be cleared manually using clearResult. Default behavior always returns false. Subclasses probably want to set a variable in processNewChildren that will be read here.
Reimplemented from org.ccnx.ccn.profiles.nameenum.EnumeratedNameList.
boolean org.ccnx.ccn.io.content.KeyDirectory.hasSupersededBlock | ( | ) | throws ContentNotReadyException |
Checks for the existence of a superseded block.
ContentNotReadyException |
void org.ccnx.ccn.io.content.KeyDirectory.initialize | ( | boolean | startEnumerating | ) | throws IOException [protected] |
We don't start enumerating until we get here.
IOException |
boolean org.ccnx.ccn.io.content.KeyDirectory.isPrivateKeyInCache | ( | ) |
Key org.ccnx.ccn.io.content.KeyDirectory.unwrapKeyViaCache | ( | byte[] | keyIDOfCachedKeytoUse | ) | throws ContentDecodingException, IOException, InvalidKeyException, NoSuchAlgorithmException [protected] |
Fast path -- once we have an idea which of our keys will unwrap this key, get it.
Can be called after enumeration, or if we have a guess of what key to use.
keyIDOfCachedKeytoUse |
IOException | ||
ContentDecodingException | ||
NoSuchAlgorithmException | ||
InvalidKeyException |