/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* ident "%Z%%M% %I% %E% SMI"
*
* Copyright (c) 1999 by Sun Microsystems, Inc.
* All rights reserved.
*
*/
/**
* The AuthBlock class models both the client and server side
* authentication blocks.
*<p>
* AuthBlocks are agnostic as to which components from a given
* message should be used in authentication. Thus each message
* must provide the correct components in the correct order.
*<p>
* These components are passed via Object[]s. The Object[] elements
* should be in externalized form, and should be ordered as stated
* in the protocol specification for auth blocks. AuthBlocks will
* add the externalized SPI string before the Object[] and the
* externalized timestamp after the vector.
*<p>
* The AuthBlock class provides a number of static convenience
* methods which operate on sets of AuthBlocks. The sets of
* AuthBlocks are stored in Hashtables, keyed by SPIs.
*/
class AuthBlock {
/**
* A convenience method for creating a set of auth blocks
* from internal data structures.
*
* @param message The ordered components of the SLP message
* over which the signature should be computed,
* in externalized (byte[]) form.
* @param lifetime The lifetime for this message, in seconds.
* @return A Hashtable of AuthBlocks, one for each SPI, null if no
* SPIs have been configured.
* @exception ServiceLocationException If a key management or crypto
* algorithm provider cannot be
* instantiated, a SYSTEM_ERROR exception
* is thrown.
* @exception IllegalArgumentException If any of the parameters are null
* or empty.
*/
throw new ServiceLocationException(
}
while (spisEnum.hasMoreElements()) {
}
return blocks;
}
/**
* A convenience method which creates a Hashtable of auth blocks
* from an input stream.
*
* @param hdr Header of message being parsed out.
* @param message The ordered components of the SLP message
* over which the signature should have been computed,
* in externalized (byte[]) form.
* @param dis Input stream with the auth block bytes queued up as the
* next thing.
* @param nBlocks Number of auth blocks to read.
* @return A Hashtable of AuthBlocks.
* @exception ServiceLocationException If anything goes wrong during
* parsing. If nBlocks is 0, the
* error code is AUTHENTICATION_ABSENT.
* @exception IllegalArgumentException If any of the parameters are null
* or empty.
* @exception IOException If DataInputStream throws it.
*/
byte nBlocks)
throws ServiceLocationException,
}
return blocks;
}
/**
* A convenience method which verifies all auth blocks in the
* input Hashtable.
*
* @param authBlocks A Hashtable containing AuthBlocks.
* @exception ServiceLocationException Thrown if authentication fails,
* with the error code
* ServiceLocationException.AUTHENTICATION_FAILED. If any
* other error occurs during authentication, the
* error code is ServiceLocationException.SYSTEM_ERROR.
* If the signature hasn't been calculated the
* authentication fails.
* @exception IllegalArgumentException If authBlocks is null or empty.
*/
while (blocks.hasMoreElements()) {
}
}
/**
* A convenience method which finds the shortest lifetime in a
* set of AuthBlocks.
*
* @param authBlocks A Hashtable containing AuthBlocks.
* @return The shortest lifetime found.
* @exception IllegalArgumentException If authBlocks is null or empty.
*/
throws IllegalArgumentException {
while (blocks.hasMoreElements()) {
}
return lifetime;
}
/**
* A convenience method which externalizes a set of AuthBlocks
* into a ByteArrayOutputStream. The number of blocks is NOT
* written onto the stream.
*
* @param hdr Header of message being externalized.
* @param authBlocks A Hashtable containing AuthBlocks.
* @param baos The output stream into which to write.
* @exception ServiceLocationException Thrown if an error occurs during
* output, with PARSE_ERROR error code.
* @exception IllegalArgumentException If any parameters are null, or
* if authBlocks is empty.
*/
while (blocks.hasMoreElements()) {
}
}
/**
* Returns the message parts obtained from the AuthBlock contructor.
* The Object[] will not have been altered. Note that all AuthBlocks
* contain the same message Object[] Object.
*
* @param authBlocks A Hashtable containing AuthBlocks.
* @return This auth block's message components Object[].
* @exception IllegalArgumentException If authBlocks is null or empty.
*/
throws IllegalArgumentException {
return ab.getMessageParts();
}
/**
* Creates a String describing all auth blocks in authBlocks.
* We dont't use toString() since that would get Hashtable.toString(),
* and we can format it a little prettier.
*
* @param authBlocks A Hashtable containing AuthBlocks.
* @return A String description of all AuthBlocks in this Hashtable
*/
if (authBlocks == null) {
return "null";
}
int cnt = 0;
while (blocks.hasMoreElements()) {
}
return desc;
}
/**
* Returns the list of SPIs configured with this 'prop', or null
* if the property hasn't been set.
*/
return null;
}
return commaSeparatedListToLinkedList(spiProp);
}
/**
* Converts a comma-separaterd list in a String to a LinkedList.
*/
while (stk_comma.hasMoreTokens()) {
}
return answer;
}
/**
* Returns true if this principal is someDH, or if this principal's
* cert has been signed by someDN.
*/
return false;
}
return false;
}
return onCertChain(
}
/**
* Checks if caDN is in ab's equivalency set, i.e. if caDN
* is in ab's cert chain.
*/
// Get cert for input DN
try {
} catch (Exception e) {
"cant_get_equivalency",
return false;
}
}
/**
* Filters out from auths all auth blocks which have not been
* signed by DNs equivalent to caDN.
*/
return null;
}
// Get cert for input DN
try {
} catch (Exception e) {
"cant_get_equivalency",
return null;
}
while (blocks.hasMoreElements()) {
return ab;
}
}
return null;
}
/**
* Gets a list of signing identities. Returns a Hashtable of
* which the keys are SPI strings (DNs) and the values
* are BSD Integers.
*/
return null;
}
/* derive DN from alias */
// escape DN
try {
} catch (ServiceLocationException e) {
// Shouldn't get here if badTag == false
}
int ibsd;
ibsd = 2;
ibsd = 1;
} else {
return null;
}
return answer;
}
/**
* Returns the cert corresponding to our signing alias.
* @@@ change this when AMI goes in to use private AMI interface.
*/
return null;
}
/* load key store */
// Can only sign with one alias, so ignore any extras
if (stk_comma.hasMoreTokens()) {
/* get keypkg for this alias */
}
return cert;
}
/**
* Creates a new AuthBlock based on the SPI and message parts.
*
* @param message The ordered components of the SLP message
* over which the signature should be computed,
* in externalized (byte[]) form.
* @param spi The SLP SPI for which to create the auth block.
* @param lifetime The lifetime for this message, in seconds.
* @exception ServiceLocationException If a key management or crypto
* algorithm provider cannot be
* instantiated, a SYSTEM_ERROR exception
* is thrown.
* @exception IllegalArgumentException If any of the parameters are null
* or empty.
*/
// init crypto provider associated with bsd
// Create the signature: create and sign the hash
try {
// @@@ how to sign for different aliases?
computeHash();
} catch (InvalidKeyException e) { // @@@ will change for AMI
throw
"cant_sign_for_spi",
new Object[] {
spi,
e.getMessage() }));
} catch (SignatureException e) {
throw
"cant_sign_for_spi",
new Object[] {
spi,
e.getMessage() }));
}
// calculate the length
abLength =
2 + // bsd
2 + // length
4 + // timestamp
}
/**
* Creates a new AuthBlock from an input stream.
*
* @param hdr The header of the message being parsed.
* @param message The ordered components of the SLP message
* over which the signature should have been computed,
* in externalized (byte[]) form.
* @param dis Input stream with the auth block bytes queued up as the
* next thing.
* @exception ServiceLocationException If anything goes wrong during
* parsing. If nBlocks is 0, the
* error code is AUTHENTICATION_ABSENT.
* @exception IllegalArgumentException If any of the parameters are null
* or empty.
* @exception IOException If DataInputStream throws it.
*/
throws ServiceLocationException,
// parse in the auth block from the input stream;
// first get the BSD and length
// get the timestamp
pos += 4;
// get the SPI
throw new ServiceLocationException(
"no_spi_string",
new Object[0]);
}
// get the structured auth block
// calculate remaining lifetime from timestamp
// Initialize the crypto provider
}
/**
* Gets the size of this auth block, after externalization, in bytes.
*
* @return The number of bytes in this auth block.
*/
int nBytes() {
return abLength;
}
/**
* Returns the message parts obtained from the AuthBlock contructor.
* The Object[] will not have been altered.
*
* @return This auth block's message components Object[].
*/
return message;
}
/**
* Verifies the signature on this auth block.
*
* @exception ServiceLocationException Thrown if authentication fails,
* with the error code
* ServiceLocationException.AUTHENTICATION_FAILED. If any
* other error occurs during authentication, the
* error code is ServiceLocationException.SYSTEM_ERROR.
* If the signature hasn't been calculated, the
* fails.
*/
// Load the keystore
try {
} catch (Exception e) {
throw
"no_keystore",
new Object[] {e.getMessage()});
}
// Unescape the SPI for cleaner logging
try {
u_DN =
} catch (ServiceLocationException e) {
}
// get cert for this spi
// check cert validity
try {
} catch (CertificateException e) {
throw new ServiceLocationException(
"invalid_cert",
}
// check the lifetime
if (lifetime == 0) {
throw new ServiceLocationException(
"timestamp_failure",
}
// make sure this SPI matches up with configured SPIs
try {
} catch (GeneralSecurityException e) {
throw new ServiceLocationException(
"cant_match_spis",
}
// check the signature
try {
} catch (InvalidKeyException ex) {
throw
"init_verify_failure",
new Object[] {
u_DN,
ex.getMessage()});
}
computeHash();
"verify_failure",
try {
throw vex;
} catch (SignatureException ex) {
throw vex;
}
}
/**
* Convert the auth block into its on-the-wire format.
*
* @param hdr The header of the message being parsed out.
* @param baos The output stream into which to write.
* @exception ServiceLocationException Thrown if an error occurs during
* output, with PARSE_ERROR error code.
* @exception IllegalArgumentException If any baos is null.
*/
// Lay out the auth block, starting with the BSD
// write out the length
// calculate and write out the timestamp
// write the SPI string
// Finish by writting the structured auth block
}
/**
* Returns the SPI associated with this auth block.
*
* @return The SLP SPI for this auth block.
*/
return spi;
}
/**
* Returns the lifetime computed from this auth block.
*
* @return The lifetime from this auth block.
*/
int getLifetime() {
return lifetime;
}
/**
* Given a BSD, sets this AuthBlock's Signature to the
* right algorithm.
*/
throws ServiceLocationException {
try {
if (bsd == 2) {
algo = "DSA";
return;
} else if (bsd == 1) {
return;
} else if (bsd == 3) {
algo = "Keyed HMAC with MD5";
}
} catch (GeneralSecurityException e) {
// system error -- no such provider
throw new ServiceLocationException(
"cant_get_security_provider",
new Object[] {
algo,
e.getMessage()});
}
// Unknown or unsupported BSD
throw new ServiceLocationException(
"cant_get_security_provider",
new Object[] {
algo,
"Unknown or unsupported BSD"});
}
/**
* throws an IllegalArgumentException if v is null or empty.
* v can be either a Hashtable or a Object[].
*/
throws IllegalArgumentException {
int size = 0;
if (v != null) {
if (v instanceof Object[]) {
} else {
// this will force a class cast exception if not a Hashtable
}
}
throw
new IllegalArgumentException(msg);
}
}
/**
* Computes a hash over the SPI String, message componenets,
* and timstamp. Which hash is used depends on which crypto
* provider was installed.
*
* This method assumes that the class variables spi, sig,
* message, and timeStamp have all been initialized. As a side
* effect, it places the externalized SPI String into spiBytes.
*/
try {
// get the SPI String bytes
// Add each message component
for (int i = 0; i < mSize; i++) {
}
// end by adding the timestamp
baosT = new ByteArrayOutputStream();
} catch (SignatureException e) {
throw new ServiceLocationException(
"cant_compute_hash",
new Object[] {e.getMessage()});
}
}
byte[] bytes = new byte[4];
long i = a << 24;
i += b << 16;
i += c << 8;
i += d;
return i;
}
}
/**
* Determines if this process' SPI configuration allows
* messages signed by 'cert' to be verified. This method
* also verifies and validates 'cert's cert chain.
*/
// get the list of configured SPIs
throw new ServiceLocationException(
}
// Get cert chain
throw new ServiceLocationException(
"no_cert_chain",
}
// validate all links in chain
int i = 0;
try {
// Add cert's own subjec to equiv set
// OK, so add to equivalency set
}
} catch (ClassCastException e) {
throw new ServiceLocationException(
"not_x509cert",
}
return;
}
// if we get here, no SPIs matched, so the authentication fails
throw new ServiceLocationException(
"cant_match_spis",
}
/**
* Determines if, given a set of SPIs 'conf_spis', we can
* verify a message signed by the Principal named by 'cert'.
*/
static private boolean configuredToVerify(
while (stk.hasMoreTokens()) {
try {
} catch (NoSuchElementException e) {
break;
}
// get CA cert to get CA Principal
try {
} catch (ServiceLocationException e) {
"cant_process_spi",
continue;
}
return true;
}
}
return false;
}
/**
* Determines if sub if equivalent to ca by getting sub's cert
* chain and walking the chain looking for ca.
* This routine does not verify the cert chain.
*/
throws ServiceLocationException {
"no_cert_chain",
try {
// Get cert keystore
// Get cert chain for subject
} catch (KeyStoreException e) {
throw ex;
}
throw ex;
}
// walk the cert chain
}
/**
* Operates the same as above, but rather than getting the cert
* chain for sub, uses a given cert chain.
*/
{
// walk the cert chain
return true;
}
}
return false;
}
/**
* Returns true if someDN is in this AuthBlock's equivalence set.
*/
}
/**
* Retrieves from the KeyStore 'ks' the X509Certificate named
* by DN.
*/
throws ServiceLocationException {
// Unescape DN
try {
} catch (ServiceLocationException e) {
throw new ServiceLocationException(
"spi_parse_error",
}
try {
} catch (ClassCastException e) {
throw new ServiceLocationException(
"not_x509cert",
} catch (KeyStoreException e) {
throw new ServiceLocationException(
"no_cert",
}
throw new ServiceLocationException(
"no_cert",
}
return cert;
}
/**
* Gets a handle to the trusted key package for this process.
*/
throws ServiceLocationException {
return keypkg;
}
/* else load key store */
try {
} catch (Exception e) {
throw new ServiceLocationException(
"no_keystore",
new Object[] {e.getMessage()});
}
return keypkg;
}
/**
* Gets a handle to a certificate repository.
*/
throws ServiceLocationException {
return keystore;
}
try {
} catch (Exception e) {
throw
"no_keystore",
new Object[] {e.getMessage()});
}
return keystore;
}
}
// Instance variables
int bsd;
int abLength;
byte[] abBytes;
byte[] spiBytes;
// cached per process
}