17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * ident	"%Z%%M%	%I%	%E% SMI"
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * Copyright (c) 1999 by Sun Microsystems, Inc.
267c478bd9Sstevel@tonic-gate  * All rights reserved.
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate package com.sun.slp;
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate import java.util.*;
337c478bd9Sstevel@tonic-gate import java.io.*;
347c478bd9Sstevel@tonic-gate import java.security.*;
357c478bd9Sstevel@tonic-gate import java.security.cert.*;
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /**
387c478bd9Sstevel@tonic-gate  * The AuthBlock class models both the client and server side
397c478bd9Sstevel@tonic-gate  * authentication blocks.
407c478bd9Sstevel@tonic-gate  *<p>
417c478bd9Sstevel@tonic-gate  * AuthBlocks are agnostic as to which components from a given
427c478bd9Sstevel@tonic-gate  * message should be used in authentication. Thus each message
437c478bd9Sstevel@tonic-gate  * must provide the correct components in the correct order.
447c478bd9Sstevel@tonic-gate  *<p>
457c478bd9Sstevel@tonic-gate  * These components are passed via Object[]s. The Object[] elements
467c478bd9Sstevel@tonic-gate  * should be in externalized form, and should be ordered as stated
477c478bd9Sstevel@tonic-gate  * in the protocol specification for auth blocks. AuthBlocks will
487c478bd9Sstevel@tonic-gate  * add the externalized SPI string before the Object[] and the
497c478bd9Sstevel@tonic-gate  * externalized timestamp after the vector.
507c478bd9Sstevel@tonic-gate  *<p>
517c478bd9Sstevel@tonic-gate  * The AuthBlock class provides a number of static convenience
527c478bd9Sstevel@tonic-gate  * methods which operate on sets of AuthBlocks. The sets of
537c478bd9Sstevel@tonic-gate  * AuthBlocks are stored in Hashtables, keyed by SPIs.
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate class AuthBlock {
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate     static private String SPI_PROPERTY = "sun.net.slp.SPIs";
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate     /**
617c478bd9Sstevel@tonic-gate      * A convenience method for creating a set of auth blocks
627c478bd9Sstevel@tonic-gate      * from internal data structures.
637c478bd9Sstevel@tonic-gate      *
647c478bd9Sstevel@tonic-gate      * @param message The ordered components of the SLP message
657c478bd9Sstevel@tonic-gate      *			over which the signature should be computed,
667c478bd9Sstevel@tonic-gate      *			in externalized (byte[]) form.
677c478bd9Sstevel@tonic-gate      * @param lifetime The lifetime for this message, in seconds.
687c478bd9Sstevel@tonic-gate      * @return A Hashtable of AuthBlocks, one for each SPI, null if no
697c478bd9Sstevel@tonic-gate      *		SPIs have been configured.
707c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If a key management or crypto
717c478bd9Sstevel@tonic-gate      *					algorithm provider cannot be
727c478bd9Sstevel@tonic-gate      *					instantiated, a SYSTEM_ERROR exception
737c478bd9Sstevel@tonic-gate      *					is thrown.
747c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any of the parameters are null
757c478bd9Sstevel@tonic-gate      *					or empty.
767c478bd9Sstevel@tonic-gate      */
makeAuthBlocks(Object[] message, int lifetime)777c478bd9Sstevel@tonic-gate     static Hashtable makeAuthBlocks(Object[] message, int lifetime)
787c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	Hashtable spis = getSignAs();
817c478bd9Sstevel@tonic-gate 	if (spis == null) {
827c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
837c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
847c478bd9Sstevel@tonic-gate 		"cant_sign", new Object[0]);
857c478bd9Sstevel@tonic-gate 	}
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	Hashtable blocks = new Hashtable();
887c478bd9Sstevel@tonic-gate 	Enumeration spisEnum = spis.keys();
897c478bd9Sstevel@tonic-gate 	while (spisEnum.hasMoreElements()) {
907c478bd9Sstevel@tonic-gate 	    String spi = (String) spisEnum.nextElement();
917c478bd9Sstevel@tonic-gate 	    int bsd = ((Integer)(spis.get(spi))).intValue();
927c478bd9Sstevel@tonic-gate 	    blocks.put(spi, new AuthBlock(message, spi, bsd, lifetime));
937c478bd9Sstevel@tonic-gate 	}
947c478bd9Sstevel@tonic-gate 	return blocks;
957c478bd9Sstevel@tonic-gate     }
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate     /**
987c478bd9Sstevel@tonic-gate      * A convenience method which creates a Hashtable of auth blocks
997c478bd9Sstevel@tonic-gate      * from an input stream.
1007c478bd9Sstevel@tonic-gate      *
1017c478bd9Sstevel@tonic-gate      * @param hdr Header of message being parsed out.
1027c478bd9Sstevel@tonic-gate      * @param message The ordered components of the SLP message
1037c478bd9Sstevel@tonic-gate      *			over which the signature should have been computed,
1047c478bd9Sstevel@tonic-gate      *			in externalized (byte[]) form.
1057c478bd9Sstevel@tonic-gate      * @param dis Input stream with the auth block bytes queued up as the
1067c478bd9Sstevel@tonic-gate      *			next thing.
1077c478bd9Sstevel@tonic-gate      * @param nBlocks Number of auth blocks to read.
1087c478bd9Sstevel@tonic-gate      * @return A Hashtable of AuthBlocks.
1097c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If anything goes wrong during
1107c478bd9Sstevel@tonic-gate      *					parsing. If nBlocks is 0, the
1117c478bd9Sstevel@tonic-gate      *					error code is AUTHENTICATION_ABSENT.
1127c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any of the parameters are null
1137c478bd9Sstevel@tonic-gate      *					or empty.
1147c478bd9Sstevel@tonic-gate      * @exception IOException If DataInputStream throws it.
1157c478bd9Sstevel@tonic-gate      */
makeAuthBlocks(SrvLocHeader hdr, Object[] message, DataInputStream dis, byte nBlocks)1167c478bd9Sstevel@tonic-gate     static Hashtable makeAuthBlocks(SrvLocHeader hdr,
1177c478bd9Sstevel@tonic-gate 				    Object[] message,
1187c478bd9Sstevel@tonic-gate 				    DataInputStream dis,
1197c478bd9Sstevel@tonic-gate 				    byte nBlocks)
1207c478bd9Sstevel@tonic-gate 	throws ServiceLocationException,
1217c478bd9Sstevel@tonic-gate 	       IllegalArgumentException,
1227c478bd9Sstevel@tonic-gate 	       IOException {
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	Hashtable blocks = new Hashtable();
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	for (byte cnt = 0; cnt < nBlocks; cnt++) {
1277c478bd9Sstevel@tonic-gate 	    AuthBlock ab = new AuthBlock(hdr, message, dis);
1287c478bd9Sstevel@tonic-gate 	    blocks.put(ab.getSPI(), ab);
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	return blocks;
1327c478bd9Sstevel@tonic-gate     }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate     /**
1357c478bd9Sstevel@tonic-gate      * A convenience method which verifies all auth blocks in the
1367c478bd9Sstevel@tonic-gate      * input Hashtable.
1377c478bd9Sstevel@tonic-gate      *
1387c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
1397c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if authentication fails,
1407c478bd9Sstevel@tonic-gate      *            with the error code
1417c478bd9Sstevel@tonic-gate      *            ServiceLocationException.AUTHENTICATION_FAILED. If any
1427c478bd9Sstevel@tonic-gate      *            other error occurs during authentication, the
1437c478bd9Sstevel@tonic-gate      *            error code is ServiceLocationException.SYSTEM_ERROR.
1447c478bd9Sstevel@tonic-gate      *            If the signature hasn't been calculated the
1457c478bd9Sstevel@tonic-gate      *		   authentication fails.
1467c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If authBlocks is null or empty.
1477c478bd9Sstevel@tonic-gate      */
verifyAll(Hashtable authBlocks)1487c478bd9Sstevel@tonic-gate     static void verifyAll(Hashtable authBlocks)
1497c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	ensureNonEmpty(authBlocks, "authBlocks");
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
1567c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
1577c478bd9Sstevel@tonic-gate 	    ab.verify();
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate     }
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate     /**
1627c478bd9Sstevel@tonic-gate      * A convenience method which finds the shortest lifetime in a
1637c478bd9Sstevel@tonic-gate      * set of AuthBlocks.
1647c478bd9Sstevel@tonic-gate      *
1657c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
1667c478bd9Sstevel@tonic-gate      * @return The shortest lifetime found.
1677c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If authBlocks is null or empty.
1687c478bd9Sstevel@tonic-gate      */
getShortestLifetime(Hashtable authBlocks)1697c478bd9Sstevel@tonic-gate     static int getShortestLifetime(Hashtable authBlocks)
1707c478bd9Sstevel@tonic-gate 	    throws IllegalArgumentException {
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	ensureNonEmpty(authBlocks, "authBlocks");
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
1757c478bd9Sstevel@tonic-gate 	int lifetime = Integer.MAX_VALUE;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
1787c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
1797c478bd9Sstevel@tonic-gate 	    int abLife = ab.getLifetime();
1807c478bd9Sstevel@tonic-gate 	    lifetime = (lifetime < abLife) ? lifetime : abLife;
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	return lifetime;
1847c478bd9Sstevel@tonic-gate     }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate     /**
1877c478bd9Sstevel@tonic-gate      * A convenience method which externalizes a set of AuthBlocks
1887c478bd9Sstevel@tonic-gate      * into a ByteArrayOutputStream. The number of blocks is NOT
1897c478bd9Sstevel@tonic-gate      * written onto the stream.
1907c478bd9Sstevel@tonic-gate      *
1917c478bd9Sstevel@tonic-gate      * @param hdr Header of message being externalized.
1927c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
1937c478bd9Sstevel@tonic-gate      * @param baos The output stream into which to write.
1947c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if an error occurs during
1957c478bd9Sstevel@tonic-gate      *					  output, with PARSE_ERROR error code.
1967c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any parameters are null, or
1977c478bd9Sstevel@tonic-gate      *					  if authBlocks is empty.
1987c478bd9Sstevel@tonic-gate      */
externalizeAll(SrvLocHeader hdr, Hashtable authBlocks, ByteArrayOutputStream baos)1997c478bd9Sstevel@tonic-gate     static void externalizeAll(SrvLocHeader hdr,
2007c478bd9Sstevel@tonic-gate 			       Hashtable authBlocks,
2017c478bd9Sstevel@tonic-gate 			       ByteArrayOutputStream baos)
2027c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	ensureNonEmpty(authBlocks, "authBlocks");
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
2097c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
2107c478bd9Sstevel@tonic-gate 	    ab.externalize(hdr, baos);
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate     }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate     /**
2157c478bd9Sstevel@tonic-gate      * Returns the message parts obtained from the AuthBlock contructor.
2167c478bd9Sstevel@tonic-gate      * The Object[] will not have been altered. Note that all AuthBlocks
2177c478bd9Sstevel@tonic-gate      * contain the same message Object[] Object.
2187c478bd9Sstevel@tonic-gate      *
2197c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
2207c478bd9Sstevel@tonic-gate      * @return This auth block's message components Object[].
2217c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If authBlocks is null or empty.
2227c478bd9Sstevel@tonic-gate      */
getContents(Hashtable authBlocks)2237c478bd9Sstevel@tonic-gate     static Object[] getContents(Hashtable authBlocks)
2247c478bd9Sstevel@tonic-gate 	throws IllegalArgumentException {
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	ensureNonEmpty(authBlocks, "authBlocks");
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
2297c478bd9Sstevel@tonic-gate 	AuthBlock ab = (AuthBlock) blocks.nextElement();
2307c478bd9Sstevel@tonic-gate 	return ab.getMessageParts();
2317c478bd9Sstevel@tonic-gate     }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate     /**
2347c478bd9Sstevel@tonic-gate      * Creates a String describing all auth blocks in authBlocks.
2357c478bd9Sstevel@tonic-gate      * We dont't use toString() since that would get Hashtable.toString(),
2367c478bd9Sstevel@tonic-gate      * and we can format it a little prettier.
2377c478bd9Sstevel@tonic-gate      *
2387c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
2397c478bd9Sstevel@tonic-gate      * @return A String description of all AuthBlocks in this Hashtable
2407c478bd9Sstevel@tonic-gate      */
desc(Hashtable authBlocks)2417c478bd9Sstevel@tonic-gate     static String desc(Hashtable authBlocks) {
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if (authBlocks == null) {
2447c478bd9Sstevel@tonic-gate 	    return "null";
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
2487c478bd9Sstevel@tonic-gate 	int size = authBlocks.size();
2497c478bd9Sstevel@tonic-gate 	String desc = size == 1 ? "1 Auth Block:\n" : size + " Auth Blocks:\n";
2507c478bd9Sstevel@tonic-gate 	int cnt = 0;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
2537c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
2547c478bd9Sstevel@tonic-gate 	    desc = desc + "             " + (cnt++) + ": " + ab.toString();
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	return desc;
2587c478bd9Sstevel@tonic-gate     }
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate     /**
2617c478bd9Sstevel@tonic-gate      * Returns the list of SPIs configured with this 'prop', or null
2627c478bd9Sstevel@tonic-gate      * if the property hasn't been set.
2637c478bd9Sstevel@tonic-gate      */
getSPIList(String prop)2647c478bd9Sstevel@tonic-gate     static LinkedList getSPIList(String prop) {
2657c478bd9Sstevel@tonic-gate 	String spiProp = System.getProperty(prop);
2667c478bd9Sstevel@tonic-gate 	if (spiProp == null) {
2677c478bd9Sstevel@tonic-gate 	    return null;
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	return commaSeparatedListToLinkedList(spiProp);
2717c478bd9Sstevel@tonic-gate     }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate     /**
2747c478bd9Sstevel@tonic-gate      * Converts a comma-separaterd list in a String to a LinkedList.
2757c478bd9Sstevel@tonic-gate      */
commaSeparatedListToLinkedList(String listStr)2767c478bd9Sstevel@tonic-gate     static LinkedList commaSeparatedListToLinkedList(String listStr) {
2777c478bd9Sstevel@tonic-gate 	StringTokenizer stk_comma = new StringTokenizer(listStr, ",");
2787c478bd9Sstevel@tonic-gate 	LinkedList answer = new LinkedList();
2797c478bd9Sstevel@tonic-gate 	while (stk_comma.hasMoreTokens()) {
2807c478bd9Sstevel@tonic-gate 	    String spi = stk_comma.nextToken();
2817c478bd9Sstevel@tonic-gate 	    answer.add(spi);
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	return answer;
2857c478bd9Sstevel@tonic-gate     }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate     /**
2887c478bd9Sstevel@tonic-gate      * Returns true if this principal is someDH, or if this principal's
2897c478bd9Sstevel@tonic-gate      * cert has been signed by someDN.
2907c478bd9Sstevel@tonic-gate      */
canSignAs(String someDN)2917c478bd9Sstevel@tonic-gate     static boolean canSignAs(String someDN) throws ServiceLocationException {
2927c478bd9Sstevel@tonic-gate 	X509Certificate myCert = getSignAsCert();
2937c478bd9Sstevel@tonic-gate 	if (myCert == null) {
2947c478bd9Sstevel@tonic-gate 	    return false;
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	KeyStore ks = getKeyStore();
2987c478bd9Sstevel@tonic-gate 	if (ks == null) {
2997c478bd9Sstevel@tonic-gate 	    return false;
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	X509Certificate cert = getCert(someDN, ks);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	return onCertChain(
3057c478bd9Sstevel@tonic-gate 		myCert.getSubjectDN().toString(), cert.getSubjectDN());
3067c478bd9Sstevel@tonic-gate     }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate     /**
3097c478bd9Sstevel@tonic-gate      * Checks if caDN is in ab's equivalency set, i.e. if caDN
3107c478bd9Sstevel@tonic-gate      * is in ab's cert chain.
3117c478bd9Sstevel@tonic-gate      */
checkEquiv(String caDN, AuthBlock ab)3127c478bd9Sstevel@tonic-gate     static boolean checkEquiv(String caDN, AuthBlock ab) {
3137c478bd9Sstevel@tonic-gate 	// Get cert for input DN
3147c478bd9Sstevel@tonic-gate 	X509Certificate caCert;
3157c478bd9Sstevel@tonic-gate 	try {
3167c478bd9Sstevel@tonic-gate 	    KeyStore ks = getKeyStore();
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	    caCert = getCert(caDN, ks);
3197c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
3207c478bd9Sstevel@tonic-gate 	    SLPConfig.getSLPConfig().writeLog(
3217c478bd9Sstevel@tonic-gate 		"cant_get_equivalency",
3227c478bd9Sstevel@tonic-gate 		new Object[] {caDN, e.getMessage()});
3237c478bd9Sstevel@tonic-gate 	    return false;
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	return ab.inEqSet(caCert.getSubjectDN());
3277c478bd9Sstevel@tonic-gate     }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate     /**
3307c478bd9Sstevel@tonic-gate      * Filters out from auths all auth blocks which have not been
3317c478bd9Sstevel@tonic-gate      * signed by DNs equivalent to caDN.
3327c478bd9Sstevel@tonic-gate      */
getEquivalentAuth(String caDN, Hashtable authBlocks)3337c478bd9Sstevel@tonic-gate     static AuthBlock getEquivalentAuth(String caDN, Hashtable authBlocks) {
3347c478bd9Sstevel@tonic-gate 	if (authBlocks.size() == 0) {
3357c478bd9Sstevel@tonic-gate 	    return null;
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	// Get cert for input DN
3397c478bd9Sstevel@tonic-gate 	X509Certificate caCert;
3407c478bd9Sstevel@tonic-gate 	try {
3417c478bd9Sstevel@tonic-gate 	    KeyStore ks = getKeyStore();
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	    caCert = getCert(caDN, ks);
3447c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
3457c478bd9Sstevel@tonic-gate 	    SLPConfig.getSLPConfig().writeLog(
3467c478bd9Sstevel@tonic-gate 		"cant_get_equivalency",
3477c478bd9Sstevel@tonic-gate 		new Object[] { caDN, e.getMessage()});
3487c478bd9Sstevel@tonic-gate 	    return null;
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
3547c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
3557c478bd9Sstevel@tonic-gate 	    if (ab.inEqSet(caCert.getSubjectDN())) {
3567c478bd9Sstevel@tonic-gate 		return ab;
3577c478bd9Sstevel@tonic-gate 	    }
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	return null;
3617c478bd9Sstevel@tonic-gate     }
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate     /**
3657c478bd9Sstevel@tonic-gate      * Gets a list of signing identities. Returns a Hashtable of
3667c478bd9Sstevel@tonic-gate      * which the keys are SPI strings (DNs) and the values
3677c478bd9Sstevel@tonic-gate      * are BSD Integers.
3687c478bd9Sstevel@tonic-gate      */
getSignAs()3697c478bd9Sstevel@tonic-gate     static Hashtable getSignAs() throws ServiceLocationException {
3707c478bd9Sstevel@tonic-gate 	X509Certificate cert = getSignAsCert();
3717c478bd9Sstevel@tonic-gate 	Hashtable answer = new Hashtable();
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	if (cert == null) {
3747c478bd9Sstevel@tonic-gate 	    return null;
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	/* derive DN from alias */
3787c478bd9Sstevel@tonic-gate 	String DN = cert.getSubjectDN().toString();
3797c478bd9Sstevel@tonic-gate 	String e_DN = null;
3807c478bd9Sstevel@tonic-gate 	// escape DN
3817c478bd9Sstevel@tonic-gate 	try {
3827c478bd9Sstevel@tonic-gate 	    e_DN = ServiceLocationAttribute.escapeAttributeString(DN, false);
3837c478bd9Sstevel@tonic-gate 	} catch (ServiceLocationException e) {
3847c478bd9Sstevel@tonic-gate 	    // Shouldn't get here if badTag == false
3857c478bd9Sstevel@tonic-gate 	    e_DN = DN;
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 	DN = e_DN;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	String alg = cert.getPublicKey().getAlgorithm();
3907c478bd9Sstevel@tonic-gate 	int ibsd;
3917c478bd9Sstevel@tonic-gate 	if (alg.equals("DSA")) {
3927c478bd9Sstevel@tonic-gate 	    ibsd = 2;
3937c478bd9Sstevel@tonic-gate 	} else if (alg.equals("RSA")) {
3947c478bd9Sstevel@tonic-gate 	    ibsd = 1;
3957c478bd9Sstevel@tonic-gate 	} else {
3967c478bd9Sstevel@tonic-gate 	    SLPConfig.getSLPConfig().writeLog("bad_alg_for_alias",
3977c478bd9Sstevel@tonic-gate 					      new Object[] {alg});
3987c478bd9Sstevel@tonic-gate 	    return null;
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	answer.put(DN, new Integer(ibsd));
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	return answer;
4047c478bd9Sstevel@tonic-gate     }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate     /**
4077c478bd9Sstevel@tonic-gate      * Returns the cert corresponding to our signing alias.
4087c478bd9Sstevel@tonic-gate      * @@@ change this when AMI goes in to use private AMI interface.
4097c478bd9Sstevel@tonic-gate      */
getSignAsCert()4107c478bd9Sstevel@tonic-gate     static X509Certificate getSignAsCert() throws ServiceLocationException {
4117c478bd9Sstevel@tonic-gate 	String spiProp = System.getProperty("sun.net.slp.signAs");
4127c478bd9Sstevel@tonic-gate 	if (spiProp == null) {
4137c478bd9Sstevel@tonic-gate 	    SLPConfig.getSLPConfig().writeLog(
4147c478bd9Sstevel@tonic-gate 		"no_spis_given", new Object[0]);
4157c478bd9Sstevel@tonic-gate 	    return null;
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	/* load key store */
4197c478bd9Sstevel@tonic-gate 	KeyStore ks = getKeyPkg();
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	StringTokenizer stk_comma = new StringTokenizer(spiProp, ",");
4227c478bd9Sstevel@tonic-gate 	X509Certificate cert = null;
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	// Can only sign with one alias, so ignore any extras
4257c478bd9Sstevel@tonic-gate 	if (stk_comma.hasMoreTokens()) {
4267c478bd9Sstevel@tonic-gate 	    String alias = stk_comma.nextToken();
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	    /* get keypkg for this alias */
4297c478bd9Sstevel@tonic-gate 	    cert = getCert(alias, ks);
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	return cert;
4337c478bd9Sstevel@tonic-gate     }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate     /**
4367c478bd9Sstevel@tonic-gate      * Creates a new AuthBlock based on the SPI and message parts.
4377c478bd9Sstevel@tonic-gate      *
4387c478bd9Sstevel@tonic-gate      * @param message The ordered components of the SLP message
4397c478bd9Sstevel@tonic-gate      *			over which the signature should be computed,
4407c478bd9Sstevel@tonic-gate      *			in externalized (byte[]) form.
4417c478bd9Sstevel@tonic-gate      * @param spi The SLP SPI for which to create the auth block.
4427c478bd9Sstevel@tonic-gate      * @param lifetime The lifetime for this message, in seconds.
4437c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If a key management or crypto
4447c478bd9Sstevel@tonic-gate      *					algorithm provider cannot be
4457c478bd9Sstevel@tonic-gate      *					instantiated, a SYSTEM_ERROR exception
4467c478bd9Sstevel@tonic-gate      *					is thrown.
4477c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any of the parameters are null
4487c478bd9Sstevel@tonic-gate      *					or empty.
4497c478bd9Sstevel@tonic-gate      */
AuthBlock(Object[] message, String spi, int bsd, int lifetime)4507c478bd9Sstevel@tonic-gate     AuthBlock(Object[] message, String spi, int bsd, int lifetime)
4517c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	ensureNonEmpty(message, "message");
4547c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(spi, "spi");
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	// init crypto provider associated with bsd
4577c478bd9Sstevel@tonic-gate 	this.bsd = bsd;
4587c478bd9Sstevel@tonic-gate 	getSecurityProvider(bsd);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	this.message = message;
4617c478bd9Sstevel@tonic-gate 	this.spi = spi;
4627c478bd9Sstevel@tonic-gate 	this.lifetime = lifetime;
4637c478bd9Sstevel@tonic-gate 	this.timeStamp = SLPConfig.currentSLPTime() + lifetime;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	// Create the signature: create and sign the hash
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	try {
4687c478bd9Sstevel@tonic-gate 	    // @@@ how to sign for different aliases?
4697c478bd9Sstevel@tonic-gate 	    sig.initSign(null);
4707c478bd9Sstevel@tonic-gate 	    computeHash();
4717c478bd9Sstevel@tonic-gate 	    abBytes = sig.sign();
4727c478bd9Sstevel@tonic-gate 	} catch (InvalidKeyException e) {	// @@@ will change for AMI
4737c478bd9Sstevel@tonic-gate 	  SLPConfig conf = SLPConfig.getSLPConfig();
474*55fea89dSDan Cross 	    throw
4757c478bd9Sstevel@tonic-gate 		new IllegalArgumentException(
4767c478bd9Sstevel@tonic-gate 				conf.formatMessage(
4777c478bd9Sstevel@tonic-gate 					"cant_sign_for_spi",
478*55fea89dSDan Cross 					new Object[] {
479*55fea89dSDan Cross 						spi,
4807c478bd9Sstevel@tonic-gate 						e.getMessage() }));
4817c478bd9Sstevel@tonic-gate 	} catch (SignatureException e) {
4827c478bd9Sstevel@tonic-gate 	  SLPConfig conf = SLPConfig.getSLPConfig();
483*55fea89dSDan Cross 	    throw
4847c478bd9Sstevel@tonic-gate 		new IllegalArgumentException(
4857c478bd9Sstevel@tonic-gate 				conf.formatMessage(
4867c478bd9Sstevel@tonic-gate 					"cant_sign_for_spi",
487*55fea89dSDan Cross 					new Object[] {
488*55fea89dSDan Cross 						spi,
4897c478bd9Sstevel@tonic-gate 						e.getMessage() }));
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	// calculate the length
4937c478bd9Sstevel@tonic-gate 	abLength =
4947c478bd9Sstevel@tonic-gate 		2 + // bsd
4957c478bd9Sstevel@tonic-gate 		2 + // length
4967c478bd9Sstevel@tonic-gate 		4 + // timestamp
4977c478bd9Sstevel@tonic-gate 		spiBytes.length + // externalized SPI string, with length
4987c478bd9Sstevel@tonic-gate 		abBytes.length; // structured auth block
4997c478bd9Sstevel@tonic-gate     }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate     /**
5027c478bd9Sstevel@tonic-gate      * Creates a new AuthBlock from an input stream.
5037c478bd9Sstevel@tonic-gate      *
5047c478bd9Sstevel@tonic-gate      * @param hdr The header of the message being parsed.
5057c478bd9Sstevel@tonic-gate      * @param message The ordered components of the SLP message
5067c478bd9Sstevel@tonic-gate      *			over which the signature should have been computed,
5077c478bd9Sstevel@tonic-gate      *			in externalized (byte[]) form.
5087c478bd9Sstevel@tonic-gate      * @param dis Input stream with the auth block bytes queued up as the
5097c478bd9Sstevel@tonic-gate      *			next thing.
5107c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If anything goes wrong during
5117c478bd9Sstevel@tonic-gate      *					parsing. If nBlocks is 0, the
5127c478bd9Sstevel@tonic-gate      *					error code is AUTHENTICATION_ABSENT.
5137c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any of the parameters are null
5147c478bd9Sstevel@tonic-gate      *					or empty.
5157c478bd9Sstevel@tonic-gate      * @exception IOException If DataInputStream throws it.
5167c478bd9Sstevel@tonic-gate      */
AuthBlock(SrvLocHeader hdr, Object[] message, DataInputStream dis)5177c478bd9Sstevel@tonic-gate     AuthBlock(SrvLocHeader hdr, Object[] message, DataInputStream dis)
5187c478bd9Sstevel@tonic-gate 	throws ServiceLocationException,
5197c478bd9Sstevel@tonic-gate 	       IllegalArgumentException,
5207c478bd9Sstevel@tonic-gate 	       IOException {
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(hdr, "hdr");
5237c478bd9Sstevel@tonic-gate 	ensureNonEmpty(message, "message");
5247c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(dis, "dis");
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	this.message = message;
5277c478bd9Sstevel@tonic-gate 	this.eqSet = new HashSet();
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	// parse in the auth block from the input stream;
5307c478bd9Sstevel@tonic-gate 	// first get the BSD and length
5317c478bd9Sstevel@tonic-gate 	bsd = hdr.getInt(dis);
5327c478bd9Sstevel@tonic-gate 	abLength = hdr.getInt(dis);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	int pos = 4;	// bsd and length have already been consumed
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	// get the timestamp
5377c478bd9Sstevel@tonic-gate 	timeStamp = getInt32(dis);
5387c478bd9Sstevel@tonic-gate 	pos += 4;
5397c478bd9Sstevel@tonic-gate 	hdr.nbytes += 4;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	// get the SPI
5427c478bd9Sstevel@tonic-gate 	StringBuffer buf = new StringBuffer();
5437c478bd9Sstevel@tonic-gate 	hdr.getString(buf, dis);
5447c478bd9Sstevel@tonic-gate 	spi = buf.toString();
5457c478bd9Sstevel@tonic-gate 	if (spi.length() == 0) {
5467c478bd9Sstevel@tonic-gate 		throw new ServiceLocationException(
5477c478bd9Sstevel@tonic-gate 		    ServiceLocationException.PARSE_ERROR,
5487c478bd9Sstevel@tonic-gate 		    "no_spi_string",
5497c478bd9Sstevel@tonic-gate 		    new Object[0]);
5507c478bd9Sstevel@tonic-gate 	}
5517c478bd9Sstevel@tonic-gate 	pos += (2 + spi.length());
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	// get the structured auth block
5547c478bd9Sstevel@tonic-gate 	abBytes = new byte[abLength - pos];
5557c478bd9Sstevel@tonic-gate 	dis.readFully(abBytes, 0, abLength - pos);
5567c478bd9Sstevel@tonic-gate 	hdr.nbytes += abBytes.length;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	// calculate remaining lifetime from timestamp
5597c478bd9Sstevel@tonic-gate 	long time = timeStamp - SLPConfig.currentSLPTime();
5607c478bd9Sstevel@tonic-gate 	time = time <= Integer.MAX_VALUE ? time : 0;	// no crazy values
5617c478bd9Sstevel@tonic-gate 	lifetime = (int) time;
5627c478bd9Sstevel@tonic-gate 	lifetime = lifetime < 0 ? 0 : lifetime;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	// Initialize the crypto provider
5657c478bd9Sstevel@tonic-gate 	getSecurityProvider(bsd);
5667c478bd9Sstevel@tonic-gate     }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate     /**
5697c478bd9Sstevel@tonic-gate      * Gets the size of this auth block, after externalization, in bytes.
5707c478bd9Sstevel@tonic-gate      *
5717c478bd9Sstevel@tonic-gate      * @return The number of bytes in this auth block.
5727c478bd9Sstevel@tonic-gate      */
5737c478bd9Sstevel@tonic-gate     int nBytes() {
5747c478bd9Sstevel@tonic-gate 	return abLength;
5757c478bd9Sstevel@tonic-gate     }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate     /**
5787c478bd9Sstevel@tonic-gate      * Returns the message parts obtained from the AuthBlock contructor.
5797c478bd9Sstevel@tonic-gate      * The Object[] will not have been altered.
5807c478bd9Sstevel@tonic-gate      *
5817c478bd9Sstevel@tonic-gate      * @return This auth block's message components Object[].
5827c478bd9Sstevel@tonic-gate      */
5837c478bd9Sstevel@tonic-gate     Object[] getMessageParts() {
5847c478bd9Sstevel@tonic-gate 	return message;
5857c478bd9Sstevel@tonic-gate     }
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate     /**
5887c478bd9Sstevel@tonic-gate      * Verifies the signature on this auth block.
5897c478bd9Sstevel@tonic-gate      *
5907c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if authentication fails,
5917c478bd9Sstevel@tonic-gate      *            with the error code
5927c478bd9Sstevel@tonic-gate      *            ServiceLocationException.AUTHENTICATION_FAILED. If any
5937c478bd9Sstevel@tonic-gate      *            other error occurs during authentication, the
5947c478bd9Sstevel@tonic-gate      *            error code is ServiceLocationException.SYSTEM_ERROR.
5957c478bd9Sstevel@tonic-gate      *            If the signature hasn't been calculated, the
5967c478bd9Sstevel@tonic-gate      *		   fails.
5977c478bd9Sstevel@tonic-gate      */
5987c478bd9Sstevel@tonic-gate     void verify() throws ServiceLocationException {
5997c478bd9Sstevel@tonic-gate 	// Load the keystore
6007c478bd9Sstevel@tonic-gate 	KeyStore ks = null;
6017c478bd9Sstevel@tonic-gate 	try {
6027c478bd9Sstevel@tonic-gate 	    ks = KeyStore.getInstance("amicerts", "SunAMI");
6037c478bd9Sstevel@tonic-gate 	    ks.load(null, null);
6047c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
605*55fea89dSDan Cross 	    throw
6067c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
6077c478bd9Sstevel@tonic-gate 			ServiceLocationException.AUTHENTICATION_FAILED,
6087c478bd9Sstevel@tonic-gate 			"no_keystore",
6097c478bd9Sstevel@tonic-gate 			new Object[] {e.getMessage()});
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	// Unescape the SPI for cleaner logging
6137c478bd9Sstevel@tonic-gate 	String u_DN = null;
6147c478bd9Sstevel@tonic-gate 	try {
6157c478bd9Sstevel@tonic-gate 	    u_DN =
6167c478bd9Sstevel@tonic-gate 		ServiceLocationAttribute.unescapeAttributeString(spi, false);
6177c478bd9Sstevel@tonic-gate 	} catch (ServiceLocationException e) {
6187c478bd9Sstevel@tonic-gate 	    u_DN = spi;
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	// get cert for this spi
6227c478bd9Sstevel@tonic-gate 	X509Certificate cert = getCert(spi, ks);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	// check cert validity
6257c478bd9Sstevel@tonic-gate 	try {
6267c478bd9Sstevel@tonic-gate 	    cert.checkValidity();
6277c478bd9Sstevel@tonic-gate 	} catch (CertificateException e) {
6287c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
6297c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
6307c478bd9Sstevel@tonic-gate 		"invalid_cert",
6317c478bd9Sstevel@tonic-gate 		new Object[] {u_DN, e.getMessage()});
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	// check the lifetime
6357c478bd9Sstevel@tonic-gate 	if (lifetime == 0) {
6367c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
6377c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
6387c478bd9Sstevel@tonic-gate 		"timestamp_failure",
6397c478bd9Sstevel@tonic-gate 		new Object[] {u_DN});
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	// make sure this SPI matches up with configured SPIs
6437c478bd9Sstevel@tonic-gate 	try {
6447c478bd9Sstevel@tonic-gate 	    checkSPIs(cert, ks);
6457c478bd9Sstevel@tonic-gate 	} catch (GeneralSecurityException e) {
6467c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
6477c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
6487c478bd9Sstevel@tonic-gate 		"cant_match_spis",
6497c478bd9Sstevel@tonic-gate 		new Object[] {cert.getSubjectDN(), e.getMessage()});
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	// check the signature
6547c478bd9Sstevel@tonic-gate 	try {
6557c478bd9Sstevel@tonic-gate 	    sig.initVerify(cert.getPublicKey());
6567c478bd9Sstevel@tonic-gate 	} catch (InvalidKeyException ex) {
657*55fea89dSDan Cross 	    throw
6587c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
6597c478bd9Sstevel@tonic-gate 			ServiceLocationException.INTERNAL_SYSTEM_ERROR,
6607c478bd9Sstevel@tonic-gate 			"init_verify_failure",
6617c478bd9Sstevel@tonic-gate 			new Object[] {
6627c478bd9Sstevel@tonic-gate 				u_DN,
6637c478bd9Sstevel@tonic-gate 				    ex.getMessage()});
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	computeHash();
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	ServiceLocationException vex =
6697c478bd9Sstevel@tonic-gate 	    new ServiceLocationException(
6707c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
6717c478bd9Sstevel@tonic-gate 		"verify_failure",
6727c478bd9Sstevel@tonic-gate 		new Object[] {u_DN});
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	try {
6757c478bd9Sstevel@tonic-gate 	    if (!sig.verify(abBytes))
6767c478bd9Sstevel@tonic-gate 		throw vex;
6777c478bd9Sstevel@tonic-gate 	} catch (SignatureException ex) {
6787c478bd9Sstevel@tonic-gate 	    throw vex;
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate     }
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate     /**
6837c478bd9Sstevel@tonic-gate      * Convert the auth block into its on-the-wire format.
6847c478bd9Sstevel@tonic-gate      *
6857c478bd9Sstevel@tonic-gate      * @param hdr The header of the message being parsed out.
6867c478bd9Sstevel@tonic-gate      * @param baos The output stream into which to write.
6877c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if an error occurs during
6887c478bd9Sstevel@tonic-gate      *					  output, with PARSE_ERROR error code.
6897c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any baos is null.
6907c478bd9Sstevel@tonic-gate      */
6917c478bd9Sstevel@tonic-gate     void externalize(SrvLocHeader hdr, ByteArrayOutputStream baos)
6927c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(hdr, "hdr");
6957c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(baos, "baos");
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	// Lay out the auth block, starting with the BSD
6987c478bd9Sstevel@tonic-gate 	hdr.putInt(bsd, baos);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	// write out the length
7017c478bd9Sstevel@tonic-gate 	hdr.putInt(abLength, baos);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	// calculate and write out the timestamp
7047c478bd9Sstevel@tonic-gate 	putInt32(timeStamp, baos);
7057c478bd9Sstevel@tonic-gate 	hdr.nbytes += 4;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	// write the SPI string
7087c478bd9Sstevel@tonic-gate 	hdr.putString(spi, baos);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	// Finish by writting the structured auth block
7117c478bd9Sstevel@tonic-gate 	baos.write(abBytes, 0, abBytes.length);
7127c478bd9Sstevel@tonic-gate 	hdr.nbytes += abBytes.length;
7137c478bd9Sstevel@tonic-gate     }
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate     /**
7167c478bd9Sstevel@tonic-gate      * Returns the SPI associated with this auth block.
7177c478bd9Sstevel@tonic-gate      *
7187c478bd9Sstevel@tonic-gate      * @return The SLP SPI for this auth block.
7197c478bd9Sstevel@tonic-gate      */
7207c478bd9Sstevel@tonic-gate     String getSPI() {
7217c478bd9Sstevel@tonic-gate 	return spi;
7227c478bd9Sstevel@tonic-gate     }
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate     /**
7257c478bd9Sstevel@tonic-gate      * Returns the lifetime computed from this auth block.
7267c478bd9Sstevel@tonic-gate      *
7277c478bd9Sstevel@tonic-gate      * @return The lifetime from this auth block.
7287c478bd9Sstevel@tonic-gate      */
7297c478bd9Sstevel@tonic-gate     int getLifetime() {
7307c478bd9Sstevel@tonic-gate 	return lifetime;
7317c478bd9Sstevel@tonic-gate     }
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate     /**
7347c478bd9Sstevel@tonic-gate      * Given a BSD, sets this AuthBlock's Signature to the
7357c478bd9Sstevel@tonic-gate      * right algorithm.
7367c478bd9Sstevel@tonic-gate      */
7377c478bd9Sstevel@tonic-gate     private void getSecurityProvider(int bsd)
7387c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	String algo = "Unknown BSD";
7417c478bd9Sstevel@tonic-gate 	try {
7427c478bd9Sstevel@tonic-gate 	    if (bsd == 2) {
7437c478bd9Sstevel@tonic-gate 		// get DSA/SHA1 provider
7447c478bd9Sstevel@tonic-gate 		algo = "DSA";
7457c478bd9Sstevel@tonic-gate 		sig = Signature.getInstance("SHA/DSA", "SunAMI");
7467c478bd9Sstevel@tonic-gate 		return;
7477c478bd9Sstevel@tonic-gate 	    } else if (bsd == 1) {
7487c478bd9Sstevel@tonic-gate 		algo = "MD5/RSA";
7497c478bd9Sstevel@tonic-gate 		sig = Signature.getInstance("MD5/RSA", "SunAMI");
7507c478bd9Sstevel@tonic-gate 		return;
7517c478bd9Sstevel@tonic-gate 	    } else if (bsd == 3) {
7527c478bd9Sstevel@tonic-gate 		algo = "Keyed HMAC with MD5";
7537c478bd9Sstevel@tonic-gate 	    }
7547c478bd9Sstevel@tonic-gate 	} catch (GeneralSecurityException e) {
7557c478bd9Sstevel@tonic-gate 	    // system error -- no such provider
7567c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
7577c478bd9Sstevel@tonic-gate 		ServiceLocationException.INTERNAL_SYSTEM_ERROR,
7587c478bd9Sstevel@tonic-gate 		"cant_get_security_provider",
7597c478bd9Sstevel@tonic-gate 		new Object[] {
7607c478bd9Sstevel@tonic-gate 			new Integer(bsd),
7617c478bd9Sstevel@tonic-gate 			algo,
7627c478bd9Sstevel@tonic-gate 			e.getMessage()});
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	// Unknown or unsupported BSD
7667c478bd9Sstevel@tonic-gate 	throw new ServiceLocationException(
7677c478bd9Sstevel@tonic-gate 	    ServiceLocationException.INTERNAL_SYSTEM_ERROR,
7687c478bd9Sstevel@tonic-gate 	    "cant_get_security_provider",
7697c478bd9Sstevel@tonic-gate 	    new Object[] {
7707c478bd9Sstevel@tonic-gate 		new Integer(bsd),
7717c478bd9Sstevel@tonic-gate 		algo,
7727c478bd9Sstevel@tonic-gate 		"Unknown or unsupported BSD"});
7737c478bd9Sstevel@tonic-gate     }
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate     /**
7767c478bd9Sstevel@tonic-gate      * throws an IllegalArgumentException if v is null or empty.
7777c478bd9Sstevel@tonic-gate      * v can be either a Hashtable or a Object[].
7787c478bd9Sstevel@tonic-gate      */
7797c478bd9Sstevel@tonic-gate     static private void ensureNonEmpty(Object v, String param)
7807c478bd9Sstevel@tonic-gate 	throws IllegalArgumentException {
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	int size = 0;
7837c478bd9Sstevel@tonic-gate 	if (v != null) {
7847c478bd9Sstevel@tonic-gate 	    if (v instanceof Object[]) {
7857c478bd9Sstevel@tonic-gate 		size = ((Object[]) v).length;
7867c478bd9Sstevel@tonic-gate 	    } else {
7877c478bd9Sstevel@tonic-gate 		// this will force a class cast exception if not a Hashtable
7887c478bd9Sstevel@tonic-gate 		size = ((Hashtable) v).size();
7897c478bd9Sstevel@tonic-gate 	    }
7907c478bd9Sstevel@tonic-gate 	}
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	if (v == null || size == 0) {
7937c478bd9Sstevel@tonic-gate 	    SLPConfig conf = SLPConfig.getSLPConfig();
794*55fea89dSDan Cross 	    String msg =
7957c478bd9Sstevel@tonic-gate 		conf.formatMessage("null_or_empty_vector",
7967c478bd9Sstevel@tonic-gate 				   new Object[] {param});
7977c478bd9Sstevel@tonic-gate 	    throw
7987c478bd9Sstevel@tonic-gate 		new IllegalArgumentException(msg);
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate     }
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate     /**
8037c478bd9Sstevel@tonic-gate      * Computes a hash over the SPI String, message componenets,
8047c478bd9Sstevel@tonic-gate      * and timstamp. Which hash is used depends on which crypto
8057c478bd9Sstevel@tonic-gate      * provider was installed.
8067c478bd9Sstevel@tonic-gate      *
8077c478bd9Sstevel@tonic-gate      * This method assumes that the class variables spi, sig,
8087c478bd9Sstevel@tonic-gate      * message, and timeStamp have all been initialized. As a side
8097c478bd9Sstevel@tonic-gate      * effect, it places the externalized SPI String into spiBytes.
8107c478bd9Sstevel@tonic-gate      */
8117c478bd9Sstevel@tonic-gate     private void computeHash() throws ServiceLocationException {
8127c478bd9Sstevel@tonic-gate 	try {
8137c478bd9Sstevel@tonic-gate 	    // get the SPI String bytes
8147c478bd9Sstevel@tonic-gate 	    ByteArrayOutputStream baosT = new ByteArrayOutputStream();
8157c478bd9Sstevel@tonic-gate 	    SrvLocHeader.putStringField(spi, baosT, Defaults.UTF8);
8167c478bd9Sstevel@tonic-gate 	    spiBytes = baosT.toByteArray();
8177c478bd9Sstevel@tonic-gate 	    sig.update(spiBytes);
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	    // Add each message component
8207c478bd9Sstevel@tonic-gate 	    int mSize = message.length;
8217c478bd9Sstevel@tonic-gate 	    for (int i = 0; i < mSize; i++) {
8227c478bd9Sstevel@tonic-gate 		sig.update((byte[]) message[i]);
8237c478bd9Sstevel@tonic-gate 	    }
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	    // end by adding the timestamp
8267c478bd9Sstevel@tonic-gate 	    baosT = new ByteArrayOutputStream();
8277c478bd9Sstevel@tonic-gate 	    putInt32(timeStamp, baosT);
8287c478bd9Sstevel@tonic-gate 	    sig.update(baosT.toByteArray());
8297c478bd9Sstevel@tonic-gate 	} catch (SignatureException e) {
8307c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
8317c478bd9Sstevel@tonic-gate 		ServiceLocationException.INTERNAL_SYSTEM_ERROR,
8327c478bd9Sstevel@tonic-gate 		"cant_compute_hash",
8337c478bd9Sstevel@tonic-gate 		new Object[] {e.getMessage()});
8347c478bd9Sstevel@tonic-gate 	}
8357c478bd9Sstevel@tonic-gate     }
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate     static private long getInt32(DataInputStream dis) throws IOException {
8387c478bd9Sstevel@tonic-gate 	byte[] bytes = new byte[4];
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	dis.readFully(bytes, 0, 4);
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	long a = (long)(bytes[0] & 0xFF);
8437c478bd9Sstevel@tonic-gate 	long b = (long)(bytes[1] & 0xFF);
8447c478bd9Sstevel@tonic-gate 	long c = (long)(bytes[2] & 0xFF);
8457c478bd9Sstevel@tonic-gate 	long d = (long)(bytes[3] & 0xFF);
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	long i = a << 24;
8487c478bd9Sstevel@tonic-gate 	i += b << 16;
8497c478bd9Sstevel@tonic-gate 	i += c << 8;
8507c478bd9Sstevel@tonic-gate 	i += d;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	return i;
8537c478bd9Sstevel@tonic-gate     }
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate     static private void putInt32(long i, ByteArrayOutputStream baos) {
8567c478bd9Sstevel@tonic-gate 	baos.write((byte) ((i >> 24) & 0xFF));
8577c478bd9Sstevel@tonic-gate 	baos.write((byte) ((i >> 16) & 0xFF));
8587c478bd9Sstevel@tonic-gate 	baos.write((byte) ((i >> 8)  & 0xFF));
8597c478bd9Sstevel@tonic-gate 	baos.write((byte) (i & 0XFF));
8607c478bd9Sstevel@tonic-gate     }
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate     /**
8637c478bd9Sstevel@tonic-gate      * Determines if this process' SPI configuration allows
8647c478bd9Sstevel@tonic-gate      * messages signed by 'cert' to be verified. This method
8657c478bd9Sstevel@tonic-gate      * also verifies and validates 'cert's cert chain.
8667c478bd9Sstevel@tonic-gate      */
8677c478bd9Sstevel@tonic-gate     private void checkSPIs(X509Certificate cert, KeyStore ks)
8687c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, GeneralSecurityException {
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	// get the list of configured SPIs
8717c478bd9Sstevel@tonic-gate 	String conf_spis = System.getProperty("sun.net.slp.SPIs");
8727c478bd9Sstevel@tonic-gate 	if (conf_spis == null) {
8737c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
8747c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
8757c478bd9Sstevel@tonic-gate 		"no_spis_configured", new Object[0]);
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	// Get cert chain
8797c478bd9Sstevel@tonic-gate 	java.security.cert.Certificate[] chain =
8807c478bd9Sstevel@tonic-gate 	    ks.getCertificateChain(cert.getSubjectDN().toString());
8817c478bd9Sstevel@tonic-gate 	if (chain == null) {
8827c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
8837c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
8847c478bd9Sstevel@tonic-gate 		"no_cert_chain",
8857c478bd9Sstevel@tonic-gate 		new Object[] {cert.getSubjectDN().toString()});
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	// validate all links in chain
8897c478bd9Sstevel@tonic-gate 	int i = 0;
8907c478bd9Sstevel@tonic-gate 	try {
8917c478bd9Sstevel@tonic-gate 	    // Add cert's own subjec to equiv set
8927c478bd9Sstevel@tonic-gate 	    eqSet.add(((X509Certificate)chain[0]).getSubjectDN());
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	    for (i = 1; i < chain.length; i++) {
8957c478bd9Sstevel@tonic-gate 		((X509Certificate)chain[i]).checkValidity();
8967c478bd9Sstevel@tonic-gate 		chain[i-1].verify(chain[i].getPublicKey(), "SunAMI");
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 		// OK, so add to equivalency set
8997c478bd9Sstevel@tonic-gate 		eqSet.add(((X509Certificate)chain[i]).getSubjectDN());
9007c478bd9Sstevel@tonic-gate 	    }
9017c478bd9Sstevel@tonic-gate 	} catch (ClassCastException e) {
9027c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
9037c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
9047c478bd9Sstevel@tonic-gate 		"not_x509cert",
9057c478bd9Sstevel@tonic-gate 		new Object[] { chain[i].getType(), e.getMessage() });
9067c478bd9Sstevel@tonic-gate 	}
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	if (configuredToVerify(chain, conf_spis, ks)) {
9097c478bd9Sstevel@tonic-gate 	    return;
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	// if we get here, no SPIs matched, so the authentication fails
9137c478bd9Sstevel@tonic-gate 	throw new ServiceLocationException(
9147c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
9157c478bd9Sstevel@tonic-gate 		"cant_match_spis",
9167c478bd9Sstevel@tonic-gate 		new Object[] {cert.getSubjectDN().toString(), ""});
9177c478bd9Sstevel@tonic-gate     }
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate     /**
9207c478bd9Sstevel@tonic-gate      * Determines if, given a set of SPIs 'conf_spis', we can
9217c478bd9Sstevel@tonic-gate      * verify a message signed by the Principal named by 'cert'.
9227c478bd9Sstevel@tonic-gate      */
9237c478bd9Sstevel@tonic-gate     static private boolean configuredToVerify(
9247c478bd9Sstevel@tonic-gate 				java.security.cert.Certificate[] chain,
9257c478bd9Sstevel@tonic-gate 				String conf_spis,
9267c478bd9Sstevel@tonic-gate 				KeyStore ks) {
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	StringTokenizer stk = new StringTokenizer(conf_spis, ",");
9297c478bd9Sstevel@tonic-gate 	while (stk.hasMoreTokens()) {
9307c478bd9Sstevel@tonic-gate 	    String spi;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	    try {
9337c478bd9Sstevel@tonic-gate 		spi = stk.nextToken();
9347c478bd9Sstevel@tonic-gate 	    } catch (NoSuchElementException e) {
9357c478bd9Sstevel@tonic-gate 		break;
9367c478bd9Sstevel@tonic-gate 	    }
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	    // get CA cert to get CA Principal
9397c478bd9Sstevel@tonic-gate 	    Principal ca;
9407c478bd9Sstevel@tonic-gate 	    try {
9417c478bd9Sstevel@tonic-gate 		X509Certificate cacert = getCert(spi, ks);
9427c478bd9Sstevel@tonic-gate 		ca = cacert.getSubjectDN();
9437c478bd9Sstevel@tonic-gate 	    } catch (ServiceLocationException e) {
9447c478bd9Sstevel@tonic-gate 		SLPConfig.getSLPConfig().writeLog(
9457c478bd9Sstevel@tonic-gate 			"cant_process_spi",
9467c478bd9Sstevel@tonic-gate 			new Object[] {spi, e.getMessage()});
9477c478bd9Sstevel@tonic-gate 		continue;
9487c478bd9Sstevel@tonic-gate 	    }
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	    if (onCertChain(ca, chain)) {
9517c478bd9Sstevel@tonic-gate 		return true;
9527c478bd9Sstevel@tonic-gate 	    }
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	return false;
9567c478bd9Sstevel@tonic-gate     }
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate     /**
9597c478bd9Sstevel@tonic-gate      * Determines if sub if equivalent to ca by getting sub's cert
9607c478bd9Sstevel@tonic-gate      * chain and walking the chain looking for ca.
9617c478bd9Sstevel@tonic-gate      * This routine does not verify the cert chain.
9627c478bd9Sstevel@tonic-gate      */
9637c478bd9Sstevel@tonic-gate     private static boolean onCertChain(String sub, Principal ca)
9647c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	java.security.cert.Certificate[] chain;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	ServiceLocationException ex = new ServiceLocationException(
9697c478bd9Sstevel@tonic-gate 			ServiceLocationException.AUTHENTICATION_UNKNOWN,
9707c478bd9Sstevel@tonic-gate 			"no_cert_chain",
9717c478bd9Sstevel@tonic-gate 			new Object[] {sub});
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	try {
9747c478bd9Sstevel@tonic-gate 	    // Get cert keystore
9757c478bd9Sstevel@tonic-gate 	    KeyStore ks = getKeyStore();
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	    // Get cert chain for subject
9787c478bd9Sstevel@tonic-gate 	    chain = ks.getCertificateChain(sub);
9797c478bd9Sstevel@tonic-gate 	} catch (KeyStoreException e) {
9807c478bd9Sstevel@tonic-gate 	    throw ex;
9817c478bd9Sstevel@tonic-gate 	}
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	if (chain == null) {
9847c478bd9Sstevel@tonic-gate 	    throw ex;
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	// walk the cert chain
9887c478bd9Sstevel@tonic-gate 	return onCertChain(ca, chain);
9897c478bd9Sstevel@tonic-gate     }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate     /**
9927c478bd9Sstevel@tonic-gate      * Operates the same as above, but rather than getting the cert
9937c478bd9Sstevel@tonic-gate      * chain for sub, uses a given cert chain.
9947c478bd9Sstevel@tonic-gate      */
9957c478bd9Sstevel@tonic-gate     private static boolean onCertChain(Principal ca,
9967c478bd9Sstevel@tonic-gate 				       java.security.cert.Certificate[] chain)
9977c478bd9Sstevel@tonic-gate     {
9987c478bd9Sstevel@tonic-gate 	// walk the cert chain
9997c478bd9Sstevel@tonic-gate 	for (int i = 0; i < chain.length; i++) {
10007c478bd9Sstevel@tonic-gate 	    Principal sub = ((X509Certificate)chain[i]).getSubjectDN();
10017c478bd9Sstevel@tonic-gate 	    if (ca.equals(sub)) {
10027c478bd9Sstevel@tonic-gate 		return true;
10037c478bd9Sstevel@tonic-gate 	    }
10047c478bd9Sstevel@tonic-gate 	}
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	return false;
10077c478bd9Sstevel@tonic-gate     }
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate     /**
10107c478bd9Sstevel@tonic-gate      * Returns true if someDN is in this AuthBlock's equivalence set.
10117c478bd9Sstevel@tonic-gate      */
10127c478bd9Sstevel@tonic-gate     private boolean inEqSet(Principal someDN) {
10137c478bd9Sstevel@tonic-gate 	return eqSet.contains(someDN);
10147c478bd9Sstevel@tonic-gate     }
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate     /**
10177c478bd9Sstevel@tonic-gate      * Retrieves from the KeyStore 'ks' the X509Certificate named
10187c478bd9Sstevel@tonic-gate      * by DN.
10197c478bd9Sstevel@tonic-gate      */
10207c478bd9Sstevel@tonic-gate     static private X509Certificate getCert(String DN, KeyStore ks)
10217c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 	X509Certificate cert = null;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	// Unescape DN
10267c478bd9Sstevel@tonic-gate 	try {
10277c478bd9Sstevel@tonic-gate 	    DN = ServiceLocationAttribute.unescapeAttributeString(DN, false);
10287c478bd9Sstevel@tonic-gate 	} catch (ServiceLocationException e) {
10297c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
10307c478bd9Sstevel@tonic-gate 		ServiceLocationException.PARSE_ERROR,
10317c478bd9Sstevel@tonic-gate 		"spi_parse_error",
10327c478bd9Sstevel@tonic-gate 		new Object[] {DN, e.getMessage()});
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	try {
10367c478bd9Sstevel@tonic-gate 	    cert = (X509Certificate)ks.getCertificate(DN);
10377c478bd9Sstevel@tonic-gate 	} catch (ClassCastException e) {
10387c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
10397c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
10407c478bd9Sstevel@tonic-gate 		"not_x509cert",
10417c478bd9Sstevel@tonic-gate 		new Object[] {cert.getType(), e.getMessage()});
10427c478bd9Sstevel@tonic-gate 	} catch (KeyStoreException e) {
10437c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
10447c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
10457c478bd9Sstevel@tonic-gate 		"no_cert",
10467c478bd9Sstevel@tonic-gate 		new Object[] {DN, e.getMessage()});
10477c478bd9Sstevel@tonic-gate 	}
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	if (cert == null) {
10507c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
10517c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
10527c478bd9Sstevel@tonic-gate 		"no_cert",
10537c478bd9Sstevel@tonic-gate 		new Object[] {DN, "" });
10547c478bd9Sstevel@tonic-gate 	}
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	return cert;
10577c478bd9Sstevel@tonic-gate     }
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate     /**
10607c478bd9Sstevel@tonic-gate      * Gets a handle to the trusted key package for this process.
10617c478bd9Sstevel@tonic-gate      */
10627c478bd9Sstevel@tonic-gate     static private synchronized KeyStore getKeyPkg()
10637c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	if (keypkg != null) {
10667c478bd9Sstevel@tonic-gate 	    return keypkg;
10677c478bd9Sstevel@tonic-gate 	}
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	/* else load key store */
10707c478bd9Sstevel@tonic-gate 	try {
10717c478bd9Sstevel@tonic-gate 	    keypkg = KeyStore.getInstance("amiks", "SunAMI");
10727c478bd9Sstevel@tonic-gate 	    keypkg.load(null, null);
10737c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
10747c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
10757c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
10767c478bd9Sstevel@tonic-gate 		"no_keystore",
10777c478bd9Sstevel@tonic-gate 		new Object[] {e.getMessage()});
10787c478bd9Sstevel@tonic-gate 	}
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	return keypkg;
10817c478bd9Sstevel@tonic-gate     }
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate     /**
10847c478bd9Sstevel@tonic-gate      * Gets a handle to a certificate repository.
10857c478bd9Sstevel@tonic-gate      */
10867c478bd9Sstevel@tonic-gate     static private synchronized KeyStore getKeyStore()
10877c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	if (keystore != null) {
10907c478bd9Sstevel@tonic-gate 	    return keystore;
10917c478bd9Sstevel@tonic-gate 	}
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	try {
10947c478bd9Sstevel@tonic-gate 	    keystore = KeyStore.getInstance("amicerts", "SunAMI");
10957c478bd9Sstevel@tonic-gate 	    keystore.load(null, null);
10967c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
1097*55fea89dSDan Cross 	    throw
10987c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
10997c478bd9Sstevel@tonic-gate 			ServiceLocationException.AUTHENTICATION_FAILED,
11007c478bd9Sstevel@tonic-gate 			"no_keystore",
11017c478bd9Sstevel@tonic-gate 			new Object[] {e.getMessage()});
11027c478bd9Sstevel@tonic-gate 	}
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	return keystore;
11057c478bd9Sstevel@tonic-gate     }
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate     public String toString() {
11087c478bd9Sstevel@tonic-gate 	return  "SPI=``" + spi + "''\n" +
11097c478bd9Sstevel@tonic-gate 		"                BSD=``" + bsd + "''\n" +
11107c478bd9Sstevel@tonic-gate 		"                timeStamp=``" + timeStamp + "''\n" +
11117c478bd9Sstevel@tonic-gate 		"                AuthBlock bytes=" + abLength + " bytes\n";
11127c478bd9Sstevel@tonic-gate     }
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate     // Instance variables
11167c478bd9Sstevel@tonic-gate     int bsd;
11177c478bd9Sstevel@tonic-gate     String spi;
11187c478bd9Sstevel@tonic-gate     Object[] message;
11197c478bd9Sstevel@tonic-gate     int lifetime;	// need both: lifetime is for optimization,
11207c478bd9Sstevel@tonic-gate     long timeStamp;	// timeStamp is needed to compute the hash
11217c478bd9Sstevel@tonic-gate     SrvLocHeader hdr;
11227c478bd9Sstevel@tonic-gate     Signature sig;
11237c478bd9Sstevel@tonic-gate     int abLength;
11247c478bd9Sstevel@tonic-gate     byte[] abBytes;
11257c478bd9Sstevel@tonic-gate     byte[] spiBytes;
11267c478bd9Sstevel@tonic-gate     HashSet eqSet;	// built only during authblock verification
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate     // cached per process
11297c478bd9Sstevel@tonic-gate     static private KeyStore keystore;	// Certificate repository
11307c478bd9Sstevel@tonic-gate     static private KeyStore keypkg;	// My own keypkg
11317c478bd9Sstevel@tonic-gate }
1132