org.ka2ddo.yaac.auth
Class YAACKeyManager

java.lang.Object
  extended by org.ka2ddo.yaac.auth.YAACKeyManager
All Implemented Interfaces:
javax.net.ssl.KeyManager, javax.net.ssl.X509KeyManager

public class YAACKeyManager
extends java.lang.Object
implements javax.net.ssl.X509KeyManager

This class stores encryption keys used for signing and verifying messages. There are two meanings of signing:

  1. public key signing with the sender's private key and verifying with their public key.
  2. secret key Hashed Message Authentication Code for signing and verifying.

This class is the repository for keys used for this signing and verifying, backed by a Java keystore. It supports:

  1. private keys with associated public key certificate chains,
  2. public key certificates of other users,
  3. secret keys of the local user or other users.
The keys stored in the keystore are associated with lists of sending station ID's and broadcast (bulletin) addressees.

It also provides the APRS message signing and verifying logic, and provides a means to associate other station's callsigns with keys and certificates. This class also provides services to create, export, import, and delete keys and certificates.

This is based on research reported by Bryan Hoyer KG6GEU in a presentation to the NW Digital Radio group on 2013-Mar-31


Nested Class Summary
static class YAACKeyManager.KeyType
          Enumeration identifying different types of encryption keys that can be stored in the KeyManager.
 
Method Summary
 java.lang.String chooseClientAlias(java.lang.String[] keyTypes, java.security.Principal[] principals, java.net.Socket socket)
           
 java.lang.String chooseServerAlias(java.lang.String algChoice, java.security.Principal[] principals, java.net.Socket socket)
           
 void createSecretKey(java.lang.String alias)
          Create a new secret (symmetric) key.
 void deleteKey(java.lang.String alias)
          Delete a key from the local keystore.
 boolean doesKeystoreExistYet()
          Test if the keystore has been created yet,
 java.lang.String[] findMatchingKeys(MessageMessage mm)
          Search the keystore for keys that match the destination addressee of the specified message.
 java.lang.String[] findMatchingKeys(java.lang.String callsign, YAACKeyManager.KeyType keyType)
          Search the keystore for keys that match the destination addressee of the specified message.
 java.lang.String[] getAliases()
          Get all key aliases stored in the keystore.
 java.lang.String[] getAssociations(java.lang.String alias)
          Get all the associated callsigns allowed to use the key specified by the alias.
 java.security.cert.X509Certificate[] getCertificateChain(java.lang.String alias)
           
 java.lang.String[] getClientAliases(java.lang.String algChoice, java.security.Principal[] principals)
           
static YAACKeyManager getInstance()
          Get the KeyManager singleton.
 java.security.Key getKey(java.lang.String alias)
          Get the key associated with the specified alias.
 YAACKeyManager.KeyType getKeyType(java.lang.String alias)
          Get the type of key associated with the specified alias.
 java.security.PrivateKey getPrivateKey(java.lang.String alias)
          Get the PrivateKey associated with the specified alias.
 java.lang.String[] getServerAliases(java.lang.String algChoice, java.security.Principal[] principals)
           
 void insertPrivateKey(java.lang.String alias, java.security.PrivateKey key, java.security.cert.Certificate[] certs)
          Insert a private key with its associated public key certificate chain.
 void insertPublicCertificateChain(java.lang.String alias, java.security.cert.CertPath chain)
          Store the public key certificates for some other station into the keystore.
 void insertSecretKey(java.lang.String alias, byte[] encoded)
          Store a byte-encoded secret (symmetric) key in the keystore.
 boolean isPasswordSet()
          Test if the backing keystore's password has been set.
static void main(java.lang.String[] args)
          unit test.
 void setAssociations(java.lang.String alias, java.lang.String[] associations)
          Get all the associated callsigns allowed to use the key specified by the alias.
 void setPassword(char[] password)
          Set the password to be used to decode keys in the backing keystore.
 void sign(AprsSignableMessage mm, java.lang.String alias)
          Sign a timestamped APRS message with the specified key.
 SignableMessage.SignatureState verify(AprsSignableMessage mm)
          Verify the signature (if any) in an APRS message against the keys in the local keystore.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Method Detail

getInstance

public static YAACKeyManager getInstance()
Get the KeyManager singleton.

Returns:
instance of KeyManager

isPasswordSet

public boolean isPasswordSet()
Test if the backing keystore's password has been set.

Returns:
boolean true if password has been successfully set

setPassword

public void setPassword(char[] password)
                 throws java.lang.NullPointerException,
                        java.io.IOException,
                        java.security.GeneralSecurityException
Set the password to be used to decode keys in the backing keystore.

Parameters:
password - char array of the password
Throws:
java.lang.NullPointerException - if password was null
java.io.IOException - if keystore file could not be read for any reason
java.security.GeneralSecurityException - if keystore file could not be decoded for any reason

doesKeystoreExistYet

public boolean doesKeystoreExistYet()
Test if the keystore has been created yet,

Returns:
boolean true if keystore backing file exists (i.e., the keystore has been created)

getKey

public java.security.Key getKey(java.lang.String alias)
                         throws java.lang.NullPointerException
Get the key associated with the specified alias.

Parameters:
alias - String alias name for a key
Returns:
the Key associated with the alias
Throws:
java.lang.NullPointerException - if the keystore's password was not successfully set yet

getAliases

public java.lang.String[] getAliases()
                              throws java.lang.NullPointerException
Get all key aliases stored in the keystore.

Returns:
array of String aliases
Throws:
java.lang.NullPointerException - if the keystore's password was not successfully set yet

getKeyType

public YAACKeyManager.KeyType getKeyType(java.lang.String alias)
                                  throws java.lang.NullPointerException
Get the type of key associated with the specified alias.

Parameters:
alias - String name associated with the desired key
Returns:
KeyType specifying the kind of key associated with the alias, or null if no key with the specified alias
Throws:
java.lang.NullPointerException - if the keystore's password was not successfully set yet

getAssociations

public java.lang.String[] getAssociations(java.lang.String alias)
Get all the associated callsigns allowed to use the key specified by the alias.

Parameters:
alias - String name of the key to query
Returns:
array of callsigns and broadcast aliases associated with the named key (possibly zero length if no associations)

setAssociations

public void setAssociations(java.lang.String alias,
                            java.lang.String[] associations)
Get all the associated callsigns allowed to use the key specified by the alias.

Parameters:
alias - String name of the key to modify
associations - array of callsign Strings to associate with named key

createSecretKey

public void createSecretKey(java.lang.String alias)
                     throws java.lang.NullPointerException,
                            java.security.KeyStoreException
Create a new secret (symmetric) key.

Parameters:
alias - String name to label the key
Throws:
java.lang.NullPointerException - if keystore password hasn't been correctly set yet
java.security.KeyStoreException - if key can't be stored in backing keystore file

insertSecretKey

public void insertSecretKey(java.lang.String alias,
                            byte[] encoded)
                     throws java.lang.NullPointerException,
                            java.security.KeyStoreException
Store a byte-encoded secret (symmetric) key in the keystore. Used to import a key generated by someone else.

Parameters:
alias - String name to associate with key
encoded - byte array of the encoded key
Throws:
java.lang.NullPointerException - if keystore password hasn't been correctly set yet
java.security.KeyStoreException - if key can't be stored in backing keystore file

insertPublicCertificateChain

public void insertPublicCertificateChain(java.lang.String alias,
                                         java.security.cert.CertPath chain)
Store the public key certificates for some other station into the keystore.

Parameters:
alias - String name to associate with this public key
chain - array of Certificates containing the public key and identifying the issuers up to the certificate authority

insertPrivateKey

public void insertPrivateKey(java.lang.String alias,
                             java.security.PrivateKey key,
                             java.security.cert.Certificate[] certs)
                      throws java.security.KeyStoreException
Insert a private key with its associated public key certificate chain.

Parameters:
alias - String name to associate with this key pair
key - PrivateKey
certs - array of Certificates listing the public key associated with the private key and the issuers up to the certificate authority
Throws:
java.security.KeyStoreException - if the key pair could not be stored

deleteKey

public void deleteKey(java.lang.String alias)
               throws java.security.KeyStoreException,
                      java.io.IOException
Delete a key from the local keystore.

Parameters:
alias - String name of the key
Throws:
java.security.KeyStoreException - if the keystore can't be modified
java.io.IOException - if the altered keystore can't be checkpointed to the backing disk file

findMatchingKeys

public java.lang.String[] findMatchingKeys(MessageMessage mm)
Search the keystore for keys that match the destination addressee of the specified message.

Parameters:
mm - APRS text MessageMessage whose destination should be looked up
Returns:
array of String names of keys matching the message destination (may be zero-length if no matches)

findMatchingKeys

public java.lang.String[] findMatchingKeys(java.lang.String callsign,
                                           YAACKeyManager.KeyType keyType)
Search the keystore for keys that match the destination addressee of the specified message.

Parameters:
callsign - String callsign to be matched against the known keys
keyType - KeyType of keys to be searched for, or null to search for all types
Returns:
array of String names of keys that are associated with the specified callsign string (may be zero-length if no matches)

sign

public void sign(AprsSignableMessage mm,
                 java.lang.String alias)
          throws java.lang.NullPointerException,
                 java.lang.IllegalStateException,
                 java.lang.IllegalArgumentException,
                 java.security.GeneralSecurityException
Sign a timestamped APRS message with the specified key.

Parameters:
mm - MessageMessage to sign
alias - String name of key to use for signature
Throws:
java.lang.NullPointerException - if keystore password hasn't been correctly set yet
java.lang.IllegalStateException - if message has already been signed
java.lang.IllegalArgumentException - if no such key for specified alias
java.security.GeneralSecurityException - if key does not exist or signature algorithm doesn't work or isn't available

verify

public SignableMessage.SignatureState verify(AprsSignableMessage mm)
                                      throws java.security.GeneralSecurityException
Verify the signature (if any) in an APRS message against the keys in the local keystore.

Parameters:
mm - MessageMessage to verify
Returns:
SignatureState of the message
Throws:
java.security.GeneralSecurityException - if key does not exist or signature algorithm doesn't work or isn't available

main

public static void main(java.lang.String[] args)
                 throws java.lang.Exception
unit test.

Parameters:
args - String array, [0] = password, [1] = alias to use for test
Throws:
java.lang.Exception - if test fails

chooseClientAlias

public java.lang.String chooseClientAlias(java.lang.String[] keyTypes,
                                          java.security.Principal[] principals,
                                          java.net.Socket socket)
Specified by:
chooseClientAlias in interface javax.net.ssl.X509KeyManager

getClientAliases

public java.lang.String[] getClientAliases(java.lang.String algChoice,
                                           java.security.Principal[] principals)
Specified by:
getClientAliases in interface javax.net.ssl.X509KeyManager

getServerAliases

public java.lang.String[] getServerAliases(java.lang.String algChoice,
                                           java.security.Principal[] principals)
Specified by:
getServerAliases in interface javax.net.ssl.X509KeyManager

chooseServerAlias

public java.lang.String chooseServerAlias(java.lang.String algChoice,
                                          java.security.Principal[] principals,
                                          java.net.Socket socket)
Specified by:
chooseServerAlias in interface javax.net.ssl.X509KeyManager

getCertificateChain

public java.security.cert.X509Certificate[] getCertificateChain(java.lang.String alias)
Specified by:
getCertificateChain in interface javax.net.ssl.X509KeyManager

getPrivateKey

public java.security.PrivateKey getPrivateKey(java.lang.String alias)
                                       throws java.lang.NullPointerException
Get the PrivateKey associated with the specified alias.

Specified by:
getPrivateKey in interface javax.net.ssl.X509KeyManager
Parameters:
alias - String name of key to look up
Returns:
PrivateKey for the alias, or null if no such key
Throws:
java.lang.NullPointerException - if the keystore has not been opened yet