xref: /illumos-gate/usr/src/lib/libslp/javalib/com/sun/slp/AuthBlock.java (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * ident	"%Z%%M%	%I%	%E% SMI"
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1999 by Sun Microsystems, Inc.
26*7c478bd9Sstevel@tonic-gate  * All rights reserved.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate package com.sun.slp;
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate import java.util.*;
33*7c478bd9Sstevel@tonic-gate import java.io.*;
34*7c478bd9Sstevel@tonic-gate import java.security.*;
35*7c478bd9Sstevel@tonic-gate import java.security.cert.*;
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate /**
38*7c478bd9Sstevel@tonic-gate  * The AuthBlock class models both the client and server side
39*7c478bd9Sstevel@tonic-gate  * authentication blocks.
40*7c478bd9Sstevel@tonic-gate  *<p>
41*7c478bd9Sstevel@tonic-gate  * AuthBlocks are agnostic as to which components from a given
42*7c478bd9Sstevel@tonic-gate  * message should be used in authentication. Thus each message
43*7c478bd9Sstevel@tonic-gate  * must provide the correct components in the correct order.
44*7c478bd9Sstevel@tonic-gate  *<p>
45*7c478bd9Sstevel@tonic-gate  * These components are passed via Object[]s. The Object[] elements
46*7c478bd9Sstevel@tonic-gate  * should be in externalized form, and should be ordered as stated
47*7c478bd9Sstevel@tonic-gate  * in the protocol specification for auth blocks. AuthBlocks will
48*7c478bd9Sstevel@tonic-gate  * add the externalized SPI string before the Object[] and the
49*7c478bd9Sstevel@tonic-gate  * externalized timestamp after the vector.
50*7c478bd9Sstevel@tonic-gate  *<p>
51*7c478bd9Sstevel@tonic-gate  * The AuthBlock class provides a number of static convenience
52*7c478bd9Sstevel@tonic-gate  * methods which operate on sets of AuthBlocks. The sets of
53*7c478bd9Sstevel@tonic-gate  * AuthBlocks are stored in Hashtables, keyed by SPIs.
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate class AuthBlock {
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate     static private String SPI_PROPERTY = "sun.net.slp.SPIs";
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate     /**
61*7c478bd9Sstevel@tonic-gate      * A convenience method for creating a set of auth blocks
62*7c478bd9Sstevel@tonic-gate      * from internal data structures.
63*7c478bd9Sstevel@tonic-gate      *
64*7c478bd9Sstevel@tonic-gate      * @param message The ordered components of the SLP message
65*7c478bd9Sstevel@tonic-gate      *			over which the signature should be computed,
66*7c478bd9Sstevel@tonic-gate      *			in externalized (byte[]) form.
67*7c478bd9Sstevel@tonic-gate      * @param lifetime The lifetime for this message, in seconds.
68*7c478bd9Sstevel@tonic-gate      * @return A Hashtable of AuthBlocks, one for each SPI, null if no
69*7c478bd9Sstevel@tonic-gate      *		SPIs have been configured.
70*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If a key management or crypto
71*7c478bd9Sstevel@tonic-gate      *					algorithm provider cannot be
72*7c478bd9Sstevel@tonic-gate      *					instantiated, a SYSTEM_ERROR exception
73*7c478bd9Sstevel@tonic-gate      *					is thrown.
74*7c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any of the parameters are null
75*7c478bd9Sstevel@tonic-gate      *					or empty.
76*7c478bd9Sstevel@tonic-gate      */
makeAuthBlocks(Object[] message, int lifetime)77*7c478bd9Sstevel@tonic-gate     static Hashtable makeAuthBlocks(Object[] message, int lifetime)
78*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 	Hashtable spis = getSignAs();
81*7c478bd9Sstevel@tonic-gate 	if (spis == null) {
82*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
83*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
84*7c478bd9Sstevel@tonic-gate 		"cant_sign", new Object[0]);
85*7c478bd9Sstevel@tonic-gate 	}
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	Hashtable blocks = new Hashtable();
88*7c478bd9Sstevel@tonic-gate 	Enumeration spisEnum = spis.keys();
89*7c478bd9Sstevel@tonic-gate 	while (spisEnum.hasMoreElements()) {
90*7c478bd9Sstevel@tonic-gate 	    String spi = (String) spisEnum.nextElement();
91*7c478bd9Sstevel@tonic-gate 	    int bsd = ((Integer)(spis.get(spi))).intValue();
92*7c478bd9Sstevel@tonic-gate 	    blocks.put(spi, new AuthBlock(message, spi, bsd, lifetime));
93*7c478bd9Sstevel@tonic-gate 	}
94*7c478bd9Sstevel@tonic-gate 	return blocks;
95*7c478bd9Sstevel@tonic-gate     }
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate     /**
98*7c478bd9Sstevel@tonic-gate      * A convenience method which creates a Hashtable of auth blocks
99*7c478bd9Sstevel@tonic-gate      * from an input stream.
100*7c478bd9Sstevel@tonic-gate      *
101*7c478bd9Sstevel@tonic-gate      * @param hdr Header of message being parsed out.
102*7c478bd9Sstevel@tonic-gate      * @param message The ordered components of the SLP message
103*7c478bd9Sstevel@tonic-gate      *			over which the signature should have been computed,
104*7c478bd9Sstevel@tonic-gate      *			in externalized (byte[]) form.
105*7c478bd9Sstevel@tonic-gate      * @param dis Input stream with the auth block bytes queued up as the
106*7c478bd9Sstevel@tonic-gate      *			next thing.
107*7c478bd9Sstevel@tonic-gate      * @param nBlocks Number of auth blocks to read.
108*7c478bd9Sstevel@tonic-gate      * @return A Hashtable of AuthBlocks.
109*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If anything goes wrong during
110*7c478bd9Sstevel@tonic-gate      *					parsing. If nBlocks is 0, the
111*7c478bd9Sstevel@tonic-gate      *					error code is AUTHENTICATION_ABSENT.
112*7c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any of the parameters are null
113*7c478bd9Sstevel@tonic-gate      *					or empty.
114*7c478bd9Sstevel@tonic-gate      * @exception IOException If DataInputStream throws it.
115*7c478bd9Sstevel@tonic-gate      */
makeAuthBlocks(SrvLocHeader hdr, Object[] message, DataInputStream dis, byte nBlocks)116*7c478bd9Sstevel@tonic-gate     static Hashtable makeAuthBlocks(SrvLocHeader hdr,
117*7c478bd9Sstevel@tonic-gate 				    Object[] message,
118*7c478bd9Sstevel@tonic-gate 				    DataInputStream dis,
119*7c478bd9Sstevel@tonic-gate 				    byte nBlocks)
120*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException,
121*7c478bd9Sstevel@tonic-gate 	       IllegalArgumentException,
122*7c478bd9Sstevel@tonic-gate 	       IOException {
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	Hashtable blocks = new Hashtable();
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	for (byte cnt = 0; cnt < nBlocks; cnt++) {
127*7c478bd9Sstevel@tonic-gate 	    AuthBlock ab = new AuthBlock(hdr, message, dis);
128*7c478bd9Sstevel@tonic-gate 	    blocks.put(ab.getSPI(), ab);
129*7c478bd9Sstevel@tonic-gate 	}
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	return blocks;
132*7c478bd9Sstevel@tonic-gate     }
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate     /**
135*7c478bd9Sstevel@tonic-gate      * A convenience method which verifies all auth blocks in the
136*7c478bd9Sstevel@tonic-gate      * input Hashtable.
137*7c478bd9Sstevel@tonic-gate      *
138*7c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
139*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if authentication fails,
140*7c478bd9Sstevel@tonic-gate      *            with the error code
141*7c478bd9Sstevel@tonic-gate      *            ServiceLocationException.AUTHENTICATION_FAILED. If any
142*7c478bd9Sstevel@tonic-gate      *            other error occurs during authentication, the
143*7c478bd9Sstevel@tonic-gate      *            error code is ServiceLocationException.SYSTEM_ERROR.
144*7c478bd9Sstevel@tonic-gate      *            If the signature hasn't been calculated the
145*7c478bd9Sstevel@tonic-gate      *		   authentication fails.
146*7c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If authBlocks is null or empty.
147*7c478bd9Sstevel@tonic-gate      */
verifyAll(Hashtable authBlocks)148*7c478bd9Sstevel@tonic-gate     static void verifyAll(Hashtable authBlocks)
149*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	ensureNonEmpty(authBlocks, "authBlocks");
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
156*7c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
157*7c478bd9Sstevel@tonic-gate 	    ab.verify();
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate     }
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate     /**
162*7c478bd9Sstevel@tonic-gate      * A convenience method which finds the shortest lifetime in a
163*7c478bd9Sstevel@tonic-gate      * set of AuthBlocks.
164*7c478bd9Sstevel@tonic-gate      *
165*7c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
166*7c478bd9Sstevel@tonic-gate      * @return The shortest lifetime found.
167*7c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If authBlocks is null or empty.
168*7c478bd9Sstevel@tonic-gate      */
getShortestLifetime(Hashtable authBlocks)169*7c478bd9Sstevel@tonic-gate     static int getShortestLifetime(Hashtable authBlocks)
170*7c478bd9Sstevel@tonic-gate 	    throws IllegalArgumentException {
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	ensureNonEmpty(authBlocks, "authBlocks");
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
175*7c478bd9Sstevel@tonic-gate 	int lifetime = Integer.MAX_VALUE;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
178*7c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
179*7c478bd9Sstevel@tonic-gate 	    int abLife = ab.getLifetime();
180*7c478bd9Sstevel@tonic-gate 	    lifetime = (lifetime < abLife) ? lifetime : abLife;
181*7c478bd9Sstevel@tonic-gate 	}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	return lifetime;
184*7c478bd9Sstevel@tonic-gate     }
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate     /**
187*7c478bd9Sstevel@tonic-gate      * A convenience method which externalizes a set of AuthBlocks
188*7c478bd9Sstevel@tonic-gate      * into a ByteArrayOutputStream. The number of blocks is NOT
189*7c478bd9Sstevel@tonic-gate      * written onto the stream.
190*7c478bd9Sstevel@tonic-gate      *
191*7c478bd9Sstevel@tonic-gate      * @param hdr Header of message being externalized.
192*7c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
193*7c478bd9Sstevel@tonic-gate      * @param baos The output stream into which to write.
194*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if an error occurs during
195*7c478bd9Sstevel@tonic-gate      *					  output, with PARSE_ERROR error code.
196*7c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any parameters are null, or
197*7c478bd9Sstevel@tonic-gate      *					  if authBlocks is empty.
198*7c478bd9Sstevel@tonic-gate      */
externalizeAll(SrvLocHeader hdr, Hashtable authBlocks, ByteArrayOutputStream baos)199*7c478bd9Sstevel@tonic-gate     static void externalizeAll(SrvLocHeader hdr,
200*7c478bd9Sstevel@tonic-gate 			       Hashtable authBlocks,
201*7c478bd9Sstevel@tonic-gate 			       ByteArrayOutputStream baos)
202*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	ensureNonEmpty(authBlocks, "authBlocks");
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
209*7c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
210*7c478bd9Sstevel@tonic-gate 	    ab.externalize(hdr, baos);
211*7c478bd9Sstevel@tonic-gate 	}
212*7c478bd9Sstevel@tonic-gate     }
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate     /**
215*7c478bd9Sstevel@tonic-gate      * Returns the message parts obtained from the AuthBlock contructor.
216*7c478bd9Sstevel@tonic-gate      * The Object[] will not have been altered. Note that all AuthBlocks
217*7c478bd9Sstevel@tonic-gate      * contain the same message Object[] Object.
218*7c478bd9Sstevel@tonic-gate      *
219*7c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
220*7c478bd9Sstevel@tonic-gate      * @return This auth block's message components Object[].
221*7c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If authBlocks is null or empty.
222*7c478bd9Sstevel@tonic-gate      */
getContents(Hashtable authBlocks)223*7c478bd9Sstevel@tonic-gate     static Object[] getContents(Hashtable authBlocks)
224*7c478bd9Sstevel@tonic-gate 	throws IllegalArgumentException {
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	ensureNonEmpty(authBlocks, "authBlocks");
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
229*7c478bd9Sstevel@tonic-gate 	AuthBlock ab = (AuthBlock) blocks.nextElement();
230*7c478bd9Sstevel@tonic-gate 	return ab.getMessageParts();
231*7c478bd9Sstevel@tonic-gate     }
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate     /**
234*7c478bd9Sstevel@tonic-gate      * Creates a String describing all auth blocks in authBlocks.
235*7c478bd9Sstevel@tonic-gate      * We dont't use toString() since that would get Hashtable.toString(),
236*7c478bd9Sstevel@tonic-gate      * and we can format it a little prettier.
237*7c478bd9Sstevel@tonic-gate      *
238*7c478bd9Sstevel@tonic-gate      * @param authBlocks A Hashtable containing AuthBlocks.
239*7c478bd9Sstevel@tonic-gate      * @return A String description of all AuthBlocks in this Hashtable
240*7c478bd9Sstevel@tonic-gate      */
desc(Hashtable authBlocks)241*7c478bd9Sstevel@tonic-gate     static String desc(Hashtable authBlocks) {
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	if (authBlocks == null) {
244*7c478bd9Sstevel@tonic-gate 	    return "null";
245*7c478bd9Sstevel@tonic-gate 	}
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
248*7c478bd9Sstevel@tonic-gate 	int size = authBlocks.size();
249*7c478bd9Sstevel@tonic-gate 	String desc = size == 1 ? "1 Auth Block:\n" : size + " Auth Blocks:\n";
250*7c478bd9Sstevel@tonic-gate 	int cnt = 0;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
253*7c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
254*7c478bd9Sstevel@tonic-gate 	    desc = desc + "             " + (cnt++) + ": " + ab.toString();
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	return desc;
258*7c478bd9Sstevel@tonic-gate     }
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate     /**
261*7c478bd9Sstevel@tonic-gate      * Returns the list of SPIs configured with this 'prop', or null
262*7c478bd9Sstevel@tonic-gate      * if the property hasn't been set.
263*7c478bd9Sstevel@tonic-gate      */
getSPIList(String prop)264*7c478bd9Sstevel@tonic-gate     static LinkedList getSPIList(String prop) {
265*7c478bd9Sstevel@tonic-gate 	String spiProp = System.getProperty(prop);
266*7c478bd9Sstevel@tonic-gate 	if (spiProp == null) {
267*7c478bd9Sstevel@tonic-gate 	    return null;
268*7c478bd9Sstevel@tonic-gate 	}
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	return commaSeparatedListToLinkedList(spiProp);
271*7c478bd9Sstevel@tonic-gate     }
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate     /**
274*7c478bd9Sstevel@tonic-gate      * Converts a comma-separaterd list in a String to a LinkedList.
275*7c478bd9Sstevel@tonic-gate      */
commaSeparatedListToLinkedList(String listStr)276*7c478bd9Sstevel@tonic-gate     static LinkedList commaSeparatedListToLinkedList(String listStr) {
277*7c478bd9Sstevel@tonic-gate 	StringTokenizer stk_comma = new StringTokenizer(listStr, ",");
278*7c478bd9Sstevel@tonic-gate 	LinkedList answer = new LinkedList();
279*7c478bd9Sstevel@tonic-gate 	while (stk_comma.hasMoreTokens()) {
280*7c478bd9Sstevel@tonic-gate 	    String spi = stk_comma.nextToken();
281*7c478bd9Sstevel@tonic-gate 	    answer.add(spi);
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	return answer;
285*7c478bd9Sstevel@tonic-gate     }
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate     /**
288*7c478bd9Sstevel@tonic-gate      * Returns true if this principal is someDH, or if this principal's
289*7c478bd9Sstevel@tonic-gate      * cert has been signed by someDN.
290*7c478bd9Sstevel@tonic-gate      */
canSignAs(String someDN)291*7c478bd9Sstevel@tonic-gate     static boolean canSignAs(String someDN) throws ServiceLocationException {
292*7c478bd9Sstevel@tonic-gate 	X509Certificate myCert = getSignAsCert();
293*7c478bd9Sstevel@tonic-gate 	if (myCert == null) {
294*7c478bd9Sstevel@tonic-gate 	    return false;
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	KeyStore ks = getKeyStore();
298*7c478bd9Sstevel@tonic-gate 	if (ks == null) {
299*7c478bd9Sstevel@tonic-gate 	    return false;
300*7c478bd9Sstevel@tonic-gate 	}
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	X509Certificate cert = getCert(someDN, ks);
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	return onCertChain(
305*7c478bd9Sstevel@tonic-gate 		myCert.getSubjectDN().toString(), cert.getSubjectDN());
306*7c478bd9Sstevel@tonic-gate     }
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate     /**
309*7c478bd9Sstevel@tonic-gate      * Checks if caDN is in ab's equivalency set, i.e. if caDN
310*7c478bd9Sstevel@tonic-gate      * is in ab's cert chain.
311*7c478bd9Sstevel@tonic-gate      */
checkEquiv(String caDN, AuthBlock ab)312*7c478bd9Sstevel@tonic-gate     static boolean checkEquiv(String caDN, AuthBlock ab) {
313*7c478bd9Sstevel@tonic-gate 	// Get cert for input DN
314*7c478bd9Sstevel@tonic-gate 	X509Certificate caCert;
315*7c478bd9Sstevel@tonic-gate 	try {
316*7c478bd9Sstevel@tonic-gate 	    KeyStore ks = getKeyStore();
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	    caCert = getCert(caDN, ks);
319*7c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
320*7c478bd9Sstevel@tonic-gate 	    SLPConfig.getSLPConfig().writeLog(
321*7c478bd9Sstevel@tonic-gate 		"cant_get_equivalency",
322*7c478bd9Sstevel@tonic-gate 		new Object[] {caDN, e.getMessage()});
323*7c478bd9Sstevel@tonic-gate 	    return false;
324*7c478bd9Sstevel@tonic-gate 	}
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	return ab.inEqSet(caCert.getSubjectDN());
327*7c478bd9Sstevel@tonic-gate     }
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate     /**
330*7c478bd9Sstevel@tonic-gate      * Filters out from auths all auth blocks which have not been
331*7c478bd9Sstevel@tonic-gate      * signed by DNs equivalent to caDN.
332*7c478bd9Sstevel@tonic-gate      */
getEquivalentAuth(String caDN, Hashtable authBlocks)333*7c478bd9Sstevel@tonic-gate     static AuthBlock getEquivalentAuth(String caDN, Hashtable authBlocks) {
334*7c478bd9Sstevel@tonic-gate 	if (authBlocks.size() == 0) {
335*7c478bd9Sstevel@tonic-gate 	    return null;
336*7c478bd9Sstevel@tonic-gate 	}
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	// Get cert for input DN
339*7c478bd9Sstevel@tonic-gate 	X509Certificate caCert;
340*7c478bd9Sstevel@tonic-gate 	try {
341*7c478bd9Sstevel@tonic-gate 	    KeyStore ks = getKeyStore();
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	    caCert = getCert(caDN, ks);
344*7c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
345*7c478bd9Sstevel@tonic-gate 	    SLPConfig.getSLPConfig().writeLog(
346*7c478bd9Sstevel@tonic-gate 		"cant_get_equivalency",
347*7c478bd9Sstevel@tonic-gate 		new Object[] { caDN, e.getMessage()});
348*7c478bd9Sstevel@tonic-gate 	    return null;
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	Enumeration blocks = authBlocks.elements();
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 	while (blocks.hasMoreElements()) {
354*7c478bd9Sstevel@tonic-gate 	    AuthBlock ab = (AuthBlock) blocks.nextElement();
355*7c478bd9Sstevel@tonic-gate 	    if (ab.inEqSet(caCert.getSubjectDN())) {
356*7c478bd9Sstevel@tonic-gate 		return ab;
357*7c478bd9Sstevel@tonic-gate 	    }
358*7c478bd9Sstevel@tonic-gate 	}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	return null;
361*7c478bd9Sstevel@tonic-gate     }
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate     /**
365*7c478bd9Sstevel@tonic-gate      * Gets a list of signing identities. Returns a Hashtable of
366*7c478bd9Sstevel@tonic-gate      * which the keys are SPI strings (DNs) and the values
367*7c478bd9Sstevel@tonic-gate      * are BSD Integers.
368*7c478bd9Sstevel@tonic-gate      */
getSignAs()369*7c478bd9Sstevel@tonic-gate     static Hashtable getSignAs() throws ServiceLocationException {
370*7c478bd9Sstevel@tonic-gate 	X509Certificate cert = getSignAsCert();
371*7c478bd9Sstevel@tonic-gate 	Hashtable answer = new Hashtable();
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	if (cert == null) {
374*7c478bd9Sstevel@tonic-gate 	    return null;
375*7c478bd9Sstevel@tonic-gate 	}
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	/* derive DN from alias */
378*7c478bd9Sstevel@tonic-gate 	String DN = cert.getSubjectDN().toString();
379*7c478bd9Sstevel@tonic-gate 	String e_DN = null;
380*7c478bd9Sstevel@tonic-gate 	// escape DN
381*7c478bd9Sstevel@tonic-gate 	try {
382*7c478bd9Sstevel@tonic-gate 	    e_DN = ServiceLocationAttribute.escapeAttributeString(DN, false);
383*7c478bd9Sstevel@tonic-gate 	} catch (ServiceLocationException e) {
384*7c478bd9Sstevel@tonic-gate 	    // Shouldn't get here if badTag == false
385*7c478bd9Sstevel@tonic-gate 	    e_DN = DN;
386*7c478bd9Sstevel@tonic-gate 	}
387*7c478bd9Sstevel@tonic-gate 	DN = e_DN;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	String alg = cert.getPublicKey().getAlgorithm();
390*7c478bd9Sstevel@tonic-gate 	int ibsd;
391*7c478bd9Sstevel@tonic-gate 	if (alg.equals("DSA")) {
392*7c478bd9Sstevel@tonic-gate 	    ibsd = 2;
393*7c478bd9Sstevel@tonic-gate 	} else if (alg.equals("RSA")) {
394*7c478bd9Sstevel@tonic-gate 	    ibsd = 1;
395*7c478bd9Sstevel@tonic-gate 	} else {
396*7c478bd9Sstevel@tonic-gate 	    SLPConfig.getSLPConfig().writeLog("bad_alg_for_alias",
397*7c478bd9Sstevel@tonic-gate 					      new Object[] {alg});
398*7c478bd9Sstevel@tonic-gate 	    return null;
399*7c478bd9Sstevel@tonic-gate 	}
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	answer.put(DN, new Integer(ibsd));
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	return answer;
404*7c478bd9Sstevel@tonic-gate     }
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate     /**
407*7c478bd9Sstevel@tonic-gate      * Returns the cert corresponding to our signing alias.
408*7c478bd9Sstevel@tonic-gate      * @@@ change this when AMI goes in to use private AMI interface.
409*7c478bd9Sstevel@tonic-gate      */
getSignAsCert()410*7c478bd9Sstevel@tonic-gate     static X509Certificate getSignAsCert() throws ServiceLocationException {
411*7c478bd9Sstevel@tonic-gate 	String spiProp = System.getProperty("sun.net.slp.signAs");
412*7c478bd9Sstevel@tonic-gate 	if (spiProp == null) {
413*7c478bd9Sstevel@tonic-gate 	    SLPConfig.getSLPConfig().writeLog(
414*7c478bd9Sstevel@tonic-gate 		"no_spis_given", new Object[0]);
415*7c478bd9Sstevel@tonic-gate 	    return null;
416*7c478bd9Sstevel@tonic-gate 	}
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	/* load key store */
419*7c478bd9Sstevel@tonic-gate 	KeyStore ks = getKeyPkg();
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	StringTokenizer stk_comma = new StringTokenizer(spiProp, ",");
422*7c478bd9Sstevel@tonic-gate 	X509Certificate cert = null;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	// Can only sign with one alias, so ignore any extras
425*7c478bd9Sstevel@tonic-gate 	if (stk_comma.hasMoreTokens()) {
426*7c478bd9Sstevel@tonic-gate 	    String alias = stk_comma.nextToken();
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	    /* get keypkg for this alias */
429*7c478bd9Sstevel@tonic-gate 	    cert = getCert(alias, ks);
430*7c478bd9Sstevel@tonic-gate 	}
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	return cert;
433*7c478bd9Sstevel@tonic-gate     }
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate     /**
436*7c478bd9Sstevel@tonic-gate      * Creates a new AuthBlock based on the SPI and message parts.
437*7c478bd9Sstevel@tonic-gate      *
438*7c478bd9Sstevel@tonic-gate      * @param message The ordered components of the SLP message
439*7c478bd9Sstevel@tonic-gate      *			over which the signature should be computed,
440*7c478bd9Sstevel@tonic-gate      *			in externalized (byte[]) form.
441*7c478bd9Sstevel@tonic-gate      * @param spi The SLP SPI for which to create the auth block.
442*7c478bd9Sstevel@tonic-gate      * @param lifetime The lifetime for this message, in seconds.
443*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If a key management or crypto
444*7c478bd9Sstevel@tonic-gate      *					algorithm provider cannot be
445*7c478bd9Sstevel@tonic-gate      *					instantiated, a SYSTEM_ERROR exception
446*7c478bd9Sstevel@tonic-gate      *					is thrown.
447*7c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any of the parameters are null
448*7c478bd9Sstevel@tonic-gate      *					or empty.
449*7c478bd9Sstevel@tonic-gate      */
AuthBlock(Object[] message, String spi, int bsd, int lifetime)450*7c478bd9Sstevel@tonic-gate     AuthBlock(Object[] message, String spi, int bsd, int lifetime)
451*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	ensureNonEmpty(message, "message");
454*7c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(spi, "spi");
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	// init crypto provider associated with bsd
457*7c478bd9Sstevel@tonic-gate 	this.bsd = bsd;
458*7c478bd9Sstevel@tonic-gate 	getSecurityProvider(bsd);
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	this.message = message;
461*7c478bd9Sstevel@tonic-gate 	this.spi = spi;
462*7c478bd9Sstevel@tonic-gate 	this.lifetime = lifetime;
463*7c478bd9Sstevel@tonic-gate 	this.timeStamp = SLPConfig.currentSLPTime() + lifetime;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	// Create the signature: create and sign the hash
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	try {
468*7c478bd9Sstevel@tonic-gate 	    // @@@ how to sign for different aliases?
469*7c478bd9Sstevel@tonic-gate 	    sig.initSign(null);
470*7c478bd9Sstevel@tonic-gate 	    computeHash();
471*7c478bd9Sstevel@tonic-gate 	    abBytes = sig.sign();
472*7c478bd9Sstevel@tonic-gate 	} catch (InvalidKeyException e) {	// @@@ will change for AMI
473*7c478bd9Sstevel@tonic-gate 	  SLPConfig conf = SLPConfig.getSLPConfig();
474*7c478bd9Sstevel@tonic-gate 	    throw
475*7c478bd9Sstevel@tonic-gate 		new IllegalArgumentException(
476*7c478bd9Sstevel@tonic-gate 				conf.formatMessage(
477*7c478bd9Sstevel@tonic-gate 					"cant_sign_for_spi",
478*7c478bd9Sstevel@tonic-gate 					new Object[] {
479*7c478bd9Sstevel@tonic-gate 						spi,
480*7c478bd9Sstevel@tonic-gate 						e.getMessage() }));
481*7c478bd9Sstevel@tonic-gate 	} catch (SignatureException e) {
482*7c478bd9Sstevel@tonic-gate 	  SLPConfig conf = SLPConfig.getSLPConfig();
483*7c478bd9Sstevel@tonic-gate 	    throw
484*7c478bd9Sstevel@tonic-gate 		new IllegalArgumentException(
485*7c478bd9Sstevel@tonic-gate 				conf.formatMessage(
486*7c478bd9Sstevel@tonic-gate 					"cant_sign_for_spi",
487*7c478bd9Sstevel@tonic-gate 					new Object[] {
488*7c478bd9Sstevel@tonic-gate 						spi,
489*7c478bd9Sstevel@tonic-gate 						e.getMessage() }));
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	// calculate the length
493*7c478bd9Sstevel@tonic-gate 	abLength =
494*7c478bd9Sstevel@tonic-gate 		2 + // bsd
495*7c478bd9Sstevel@tonic-gate 		2 + // length
496*7c478bd9Sstevel@tonic-gate 		4 + // timestamp
497*7c478bd9Sstevel@tonic-gate 		spiBytes.length + // externalized SPI string, with length
498*7c478bd9Sstevel@tonic-gate 		abBytes.length; // structured auth block
499*7c478bd9Sstevel@tonic-gate     }
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate     /**
502*7c478bd9Sstevel@tonic-gate      * Creates a new AuthBlock from an input stream.
503*7c478bd9Sstevel@tonic-gate      *
504*7c478bd9Sstevel@tonic-gate      * @param hdr The header of the message being parsed.
505*7c478bd9Sstevel@tonic-gate      * @param message The ordered components of the SLP message
506*7c478bd9Sstevel@tonic-gate      *			over which the signature should have been computed,
507*7c478bd9Sstevel@tonic-gate      *			in externalized (byte[]) form.
508*7c478bd9Sstevel@tonic-gate      * @param dis Input stream with the auth block bytes queued up as the
509*7c478bd9Sstevel@tonic-gate      *			next thing.
510*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If anything goes wrong during
511*7c478bd9Sstevel@tonic-gate      *					parsing. If nBlocks is 0, the
512*7c478bd9Sstevel@tonic-gate      *					error code is AUTHENTICATION_ABSENT.
513*7c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any of the parameters are null
514*7c478bd9Sstevel@tonic-gate      *					or empty.
515*7c478bd9Sstevel@tonic-gate      * @exception IOException If DataInputStream throws it.
516*7c478bd9Sstevel@tonic-gate      */
AuthBlock(SrvLocHeader hdr, Object[] message, DataInputStream dis)517*7c478bd9Sstevel@tonic-gate     AuthBlock(SrvLocHeader hdr, Object[] message, DataInputStream dis)
518*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException,
519*7c478bd9Sstevel@tonic-gate 	       IllegalArgumentException,
520*7c478bd9Sstevel@tonic-gate 	       IOException {
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(hdr, "hdr");
523*7c478bd9Sstevel@tonic-gate 	ensureNonEmpty(message, "message");
524*7c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(dis, "dis");
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	this.message = message;
527*7c478bd9Sstevel@tonic-gate 	this.eqSet = new HashSet();
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	// parse in the auth block from the input stream;
530*7c478bd9Sstevel@tonic-gate 	// first get the BSD and length
531*7c478bd9Sstevel@tonic-gate 	bsd = hdr.getInt(dis);
532*7c478bd9Sstevel@tonic-gate 	abLength = hdr.getInt(dis);
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	int pos = 4;	// bsd and length have already been consumed
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	// get the timestamp
537*7c478bd9Sstevel@tonic-gate 	timeStamp = getInt32(dis);
538*7c478bd9Sstevel@tonic-gate 	pos += 4;
539*7c478bd9Sstevel@tonic-gate 	hdr.nbytes += 4;
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 	// get the SPI
542*7c478bd9Sstevel@tonic-gate 	StringBuffer buf = new StringBuffer();
543*7c478bd9Sstevel@tonic-gate 	hdr.getString(buf, dis);
544*7c478bd9Sstevel@tonic-gate 	spi = buf.toString();
545*7c478bd9Sstevel@tonic-gate 	if (spi.length() == 0) {
546*7c478bd9Sstevel@tonic-gate 		throw new ServiceLocationException(
547*7c478bd9Sstevel@tonic-gate 		    ServiceLocationException.PARSE_ERROR,
548*7c478bd9Sstevel@tonic-gate 		    "no_spi_string",
549*7c478bd9Sstevel@tonic-gate 		    new Object[0]);
550*7c478bd9Sstevel@tonic-gate 	}
551*7c478bd9Sstevel@tonic-gate 	pos += (2 + spi.length());
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	// get the structured auth block
554*7c478bd9Sstevel@tonic-gate 	abBytes = new byte[abLength - pos];
555*7c478bd9Sstevel@tonic-gate 	dis.readFully(abBytes, 0, abLength - pos);
556*7c478bd9Sstevel@tonic-gate 	hdr.nbytes += abBytes.length;
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	// calculate remaining lifetime from timestamp
559*7c478bd9Sstevel@tonic-gate 	long time = timeStamp - SLPConfig.currentSLPTime();
560*7c478bd9Sstevel@tonic-gate 	time = time <= Integer.MAX_VALUE ? time : 0;	// no crazy values
561*7c478bd9Sstevel@tonic-gate 	lifetime = (int) time;
562*7c478bd9Sstevel@tonic-gate 	lifetime = lifetime < 0 ? 0 : lifetime;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	// Initialize the crypto provider
565*7c478bd9Sstevel@tonic-gate 	getSecurityProvider(bsd);
566*7c478bd9Sstevel@tonic-gate     }
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate     /**
569*7c478bd9Sstevel@tonic-gate      * Gets the size of this auth block, after externalization, in bytes.
570*7c478bd9Sstevel@tonic-gate      *
571*7c478bd9Sstevel@tonic-gate      * @return The number of bytes in this auth block.
572*7c478bd9Sstevel@tonic-gate      */
573*7c478bd9Sstevel@tonic-gate     int nBytes() {
574*7c478bd9Sstevel@tonic-gate 	return abLength;
575*7c478bd9Sstevel@tonic-gate     }
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate     /**
578*7c478bd9Sstevel@tonic-gate      * Returns the message parts obtained from the AuthBlock contructor.
579*7c478bd9Sstevel@tonic-gate      * The Object[] will not have been altered.
580*7c478bd9Sstevel@tonic-gate      *
581*7c478bd9Sstevel@tonic-gate      * @return This auth block's message components Object[].
582*7c478bd9Sstevel@tonic-gate      */
583*7c478bd9Sstevel@tonic-gate     Object[] getMessageParts() {
584*7c478bd9Sstevel@tonic-gate 	return message;
585*7c478bd9Sstevel@tonic-gate     }
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate     /**
588*7c478bd9Sstevel@tonic-gate      * Verifies the signature on this auth block.
589*7c478bd9Sstevel@tonic-gate      *
590*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if authentication fails,
591*7c478bd9Sstevel@tonic-gate      *            with the error code
592*7c478bd9Sstevel@tonic-gate      *            ServiceLocationException.AUTHENTICATION_FAILED. If any
593*7c478bd9Sstevel@tonic-gate      *            other error occurs during authentication, the
594*7c478bd9Sstevel@tonic-gate      *            error code is ServiceLocationException.SYSTEM_ERROR.
595*7c478bd9Sstevel@tonic-gate      *            If the signature hasn't been calculated, the
596*7c478bd9Sstevel@tonic-gate      *		   fails.
597*7c478bd9Sstevel@tonic-gate      */
598*7c478bd9Sstevel@tonic-gate     void verify() throws ServiceLocationException {
599*7c478bd9Sstevel@tonic-gate 	// Load the keystore
600*7c478bd9Sstevel@tonic-gate 	KeyStore ks = null;
601*7c478bd9Sstevel@tonic-gate 	try {
602*7c478bd9Sstevel@tonic-gate 	    ks = KeyStore.getInstance("amicerts", "SunAMI");
603*7c478bd9Sstevel@tonic-gate 	    ks.load(null, null);
604*7c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
605*7c478bd9Sstevel@tonic-gate 	    throw
606*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
607*7c478bd9Sstevel@tonic-gate 			ServiceLocationException.AUTHENTICATION_FAILED,
608*7c478bd9Sstevel@tonic-gate 			"no_keystore",
609*7c478bd9Sstevel@tonic-gate 			new Object[] {e.getMessage()});
610*7c478bd9Sstevel@tonic-gate 	}
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	// Unescape the SPI for cleaner logging
613*7c478bd9Sstevel@tonic-gate 	String u_DN = null;
614*7c478bd9Sstevel@tonic-gate 	try {
615*7c478bd9Sstevel@tonic-gate 	    u_DN =
616*7c478bd9Sstevel@tonic-gate 		ServiceLocationAttribute.unescapeAttributeString(spi, false);
617*7c478bd9Sstevel@tonic-gate 	} catch (ServiceLocationException e) {
618*7c478bd9Sstevel@tonic-gate 	    u_DN = spi;
619*7c478bd9Sstevel@tonic-gate 	}
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 	// get cert for this spi
622*7c478bd9Sstevel@tonic-gate 	X509Certificate cert = getCert(spi, ks);
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	// check cert validity
625*7c478bd9Sstevel@tonic-gate 	try {
626*7c478bd9Sstevel@tonic-gate 	    cert.checkValidity();
627*7c478bd9Sstevel@tonic-gate 	} catch (CertificateException e) {
628*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
629*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
630*7c478bd9Sstevel@tonic-gate 		"invalid_cert",
631*7c478bd9Sstevel@tonic-gate 		new Object[] {u_DN, e.getMessage()});
632*7c478bd9Sstevel@tonic-gate 	}
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	// check the lifetime
635*7c478bd9Sstevel@tonic-gate 	if (lifetime == 0) {
636*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
637*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
638*7c478bd9Sstevel@tonic-gate 		"timestamp_failure",
639*7c478bd9Sstevel@tonic-gate 		new Object[] {u_DN});
640*7c478bd9Sstevel@tonic-gate 	}
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	// make sure this SPI matches up with configured SPIs
643*7c478bd9Sstevel@tonic-gate 	try {
644*7c478bd9Sstevel@tonic-gate 	    checkSPIs(cert, ks);
645*7c478bd9Sstevel@tonic-gate 	} catch (GeneralSecurityException e) {
646*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
647*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
648*7c478bd9Sstevel@tonic-gate 		"cant_match_spis",
649*7c478bd9Sstevel@tonic-gate 		new Object[] {cert.getSubjectDN(), e.getMessage()});
650*7c478bd9Sstevel@tonic-gate 	}
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	// check the signature
654*7c478bd9Sstevel@tonic-gate 	try {
655*7c478bd9Sstevel@tonic-gate 	    sig.initVerify(cert.getPublicKey());
656*7c478bd9Sstevel@tonic-gate 	} catch (InvalidKeyException ex) {
657*7c478bd9Sstevel@tonic-gate 	    throw
658*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
659*7c478bd9Sstevel@tonic-gate 			ServiceLocationException.INTERNAL_SYSTEM_ERROR,
660*7c478bd9Sstevel@tonic-gate 			"init_verify_failure",
661*7c478bd9Sstevel@tonic-gate 			new Object[] {
662*7c478bd9Sstevel@tonic-gate 				u_DN,
663*7c478bd9Sstevel@tonic-gate 				    ex.getMessage()});
664*7c478bd9Sstevel@tonic-gate 	}
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	computeHash();
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	ServiceLocationException vex =
669*7c478bd9Sstevel@tonic-gate 	    new ServiceLocationException(
670*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
671*7c478bd9Sstevel@tonic-gate 		"verify_failure",
672*7c478bd9Sstevel@tonic-gate 		new Object[] {u_DN});
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	try {
675*7c478bd9Sstevel@tonic-gate 	    if (!sig.verify(abBytes))
676*7c478bd9Sstevel@tonic-gate 		throw vex;
677*7c478bd9Sstevel@tonic-gate 	} catch (SignatureException ex) {
678*7c478bd9Sstevel@tonic-gate 	    throw vex;
679*7c478bd9Sstevel@tonic-gate 	}
680*7c478bd9Sstevel@tonic-gate     }
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate     /**
683*7c478bd9Sstevel@tonic-gate      * Convert the auth block into its on-the-wire format.
684*7c478bd9Sstevel@tonic-gate      *
685*7c478bd9Sstevel@tonic-gate      * @param hdr The header of the message being parsed out.
686*7c478bd9Sstevel@tonic-gate      * @param baos The output stream into which to write.
687*7c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if an error occurs during
688*7c478bd9Sstevel@tonic-gate      *					  output, with PARSE_ERROR error code.
689*7c478bd9Sstevel@tonic-gate      * @exception IllegalArgumentException If any baos is null.
690*7c478bd9Sstevel@tonic-gate      */
691*7c478bd9Sstevel@tonic-gate     void externalize(SrvLocHeader hdr, ByteArrayOutputStream baos)
692*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IllegalArgumentException {
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(hdr, "hdr");
695*7c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(baos, "baos");
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	// Lay out the auth block, starting with the BSD
698*7c478bd9Sstevel@tonic-gate 	hdr.putInt(bsd, baos);
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	// write out the length
701*7c478bd9Sstevel@tonic-gate 	hdr.putInt(abLength, baos);
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	// calculate and write out the timestamp
704*7c478bd9Sstevel@tonic-gate 	putInt32(timeStamp, baos);
705*7c478bd9Sstevel@tonic-gate 	hdr.nbytes += 4;
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	// write the SPI string
708*7c478bd9Sstevel@tonic-gate 	hdr.putString(spi, baos);
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	// Finish by writting the structured auth block
711*7c478bd9Sstevel@tonic-gate 	baos.write(abBytes, 0, abBytes.length);
712*7c478bd9Sstevel@tonic-gate 	hdr.nbytes += abBytes.length;
713*7c478bd9Sstevel@tonic-gate     }
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate     /**
716*7c478bd9Sstevel@tonic-gate      * Returns the SPI associated with this auth block.
717*7c478bd9Sstevel@tonic-gate      *
718*7c478bd9Sstevel@tonic-gate      * @return The SLP SPI for this auth block.
719*7c478bd9Sstevel@tonic-gate      */
720*7c478bd9Sstevel@tonic-gate     String getSPI() {
721*7c478bd9Sstevel@tonic-gate 	return spi;
722*7c478bd9Sstevel@tonic-gate     }
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate     /**
725*7c478bd9Sstevel@tonic-gate      * Returns the lifetime computed from this auth block.
726*7c478bd9Sstevel@tonic-gate      *
727*7c478bd9Sstevel@tonic-gate      * @return The lifetime from this auth block.
728*7c478bd9Sstevel@tonic-gate      */
729*7c478bd9Sstevel@tonic-gate     int getLifetime() {
730*7c478bd9Sstevel@tonic-gate 	return lifetime;
731*7c478bd9Sstevel@tonic-gate     }
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate     /**
734*7c478bd9Sstevel@tonic-gate      * Given a BSD, sets this AuthBlock's Signature to the
735*7c478bd9Sstevel@tonic-gate      * right algorithm.
736*7c478bd9Sstevel@tonic-gate      */
737*7c478bd9Sstevel@tonic-gate     private void getSecurityProvider(int bsd)
738*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	String algo = "Unknown BSD";
741*7c478bd9Sstevel@tonic-gate 	try {
742*7c478bd9Sstevel@tonic-gate 	    if (bsd == 2) {
743*7c478bd9Sstevel@tonic-gate 		// get DSA/SHA1 provider
744*7c478bd9Sstevel@tonic-gate 		algo = "DSA";
745*7c478bd9Sstevel@tonic-gate 		sig = Signature.getInstance("SHA/DSA", "SunAMI");
746*7c478bd9Sstevel@tonic-gate 		return;
747*7c478bd9Sstevel@tonic-gate 	    } else if (bsd == 1) {
748*7c478bd9Sstevel@tonic-gate 		algo = "MD5/RSA";
749*7c478bd9Sstevel@tonic-gate 		sig = Signature.getInstance("MD5/RSA", "SunAMI");
750*7c478bd9Sstevel@tonic-gate 		return;
751*7c478bd9Sstevel@tonic-gate 	    } else if (bsd == 3) {
752*7c478bd9Sstevel@tonic-gate 		algo = "Keyed HMAC with MD5";
753*7c478bd9Sstevel@tonic-gate 	    }
754*7c478bd9Sstevel@tonic-gate 	} catch (GeneralSecurityException e) {
755*7c478bd9Sstevel@tonic-gate 	    // system error -- no such provider
756*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
757*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.INTERNAL_SYSTEM_ERROR,
758*7c478bd9Sstevel@tonic-gate 		"cant_get_security_provider",
759*7c478bd9Sstevel@tonic-gate 		new Object[] {
760*7c478bd9Sstevel@tonic-gate 			new Integer(bsd),
761*7c478bd9Sstevel@tonic-gate 			algo,
762*7c478bd9Sstevel@tonic-gate 			e.getMessage()});
763*7c478bd9Sstevel@tonic-gate 	}
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 	// Unknown or unsupported BSD
766*7c478bd9Sstevel@tonic-gate 	throw new ServiceLocationException(
767*7c478bd9Sstevel@tonic-gate 	    ServiceLocationException.INTERNAL_SYSTEM_ERROR,
768*7c478bd9Sstevel@tonic-gate 	    "cant_get_security_provider",
769*7c478bd9Sstevel@tonic-gate 	    new Object[] {
770*7c478bd9Sstevel@tonic-gate 		new Integer(bsd),
771*7c478bd9Sstevel@tonic-gate 		algo,
772*7c478bd9Sstevel@tonic-gate 		"Unknown or unsupported BSD"});
773*7c478bd9Sstevel@tonic-gate     }
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate     /**
776*7c478bd9Sstevel@tonic-gate      * throws an IllegalArgumentException if v is null or empty.
777*7c478bd9Sstevel@tonic-gate      * v can be either a Hashtable or a Object[].
778*7c478bd9Sstevel@tonic-gate      */
779*7c478bd9Sstevel@tonic-gate     static private void ensureNonEmpty(Object v, String param)
780*7c478bd9Sstevel@tonic-gate 	throws IllegalArgumentException {
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 	int size = 0;
783*7c478bd9Sstevel@tonic-gate 	if (v != null) {
784*7c478bd9Sstevel@tonic-gate 	    if (v instanceof Object[]) {
785*7c478bd9Sstevel@tonic-gate 		size = ((Object[]) v).length;
786*7c478bd9Sstevel@tonic-gate 	    } else {
787*7c478bd9Sstevel@tonic-gate 		// this will force a class cast exception if not a Hashtable
788*7c478bd9Sstevel@tonic-gate 		size = ((Hashtable) v).size();
789*7c478bd9Sstevel@tonic-gate 	    }
790*7c478bd9Sstevel@tonic-gate 	}
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	if (v == null || size == 0) {
793*7c478bd9Sstevel@tonic-gate 	    SLPConfig conf = SLPConfig.getSLPConfig();
794*7c478bd9Sstevel@tonic-gate 	    String msg =
795*7c478bd9Sstevel@tonic-gate 		conf.formatMessage("null_or_empty_vector",
796*7c478bd9Sstevel@tonic-gate 				   new Object[] {param});
797*7c478bd9Sstevel@tonic-gate 	    throw
798*7c478bd9Sstevel@tonic-gate 		new IllegalArgumentException(msg);
799*7c478bd9Sstevel@tonic-gate 	}
800*7c478bd9Sstevel@tonic-gate     }
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate     /**
803*7c478bd9Sstevel@tonic-gate      * Computes a hash over the SPI String, message componenets,
804*7c478bd9Sstevel@tonic-gate      * and timstamp. Which hash is used depends on which crypto
805*7c478bd9Sstevel@tonic-gate      * provider was installed.
806*7c478bd9Sstevel@tonic-gate      *
807*7c478bd9Sstevel@tonic-gate      * This method assumes that the class variables spi, sig,
808*7c478bd9Sstevel@tonic-gate      * message, and timeStamp have all been initialized. As a side
809*7c478bd9Sstevel@tonic-gate      * effect, it places the externalized SPI String into spiBytes.
810*7c478bd9Sstevel@tonic-gate      */
811*7c478bd9Sstevel@tonic-gate     private void computeHash() throws ServiceLocationException {
812*7c478bd9Sstevel@tonic-gate 	try {
813*7c478bd9Sstevel@tonic-gate 	    // get the SPI String bytes
814*7c478bd9Sstevel@tonic-gate 	    ByteArrayOutputStream baosT = new ByteArrayOutputStream();
815*7c478bd9Sstevel@tonic-gate 	    SrvLocHeader.putStringField(spi, baosT, Defaults.UTF8);
816*7c478bd9Sstevel@tonic-gate 	    spiBytes = baosT.toByteArray();
817*7c478bd9Sstevel@tonic-gate 	    sig.update(spiBytes);
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	    // Add each message component
820*7c478bd9Sstevel@tonic-gate 	    int mSize = message.length;
821*7c478bd9Sstevel@tonic-gate 	    for (int i = 0; i < mSize; i++) {
822*7c478bd9Sstevel@tonic-gate 		sig.update((byte[]) message[i]);
823*7c478bd9Sstevel@tonic-gate 	    }
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	    // end by adding the timestamp
826*7c478bd9Sstevel@tonic-gate 	    baosT = new ByteArrayOutputStream();
827*7c478bd9Sstevel@tonic-gate 	    putInt32(timeStamp, baosT);
828*7c478bd9Sstevel@tonic-gate 	    sig.update(baosT.toByteArray());
829*7c478bd9Sstevel@tonic-gate 	} catch (SignatureException e) {
830*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
831*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.INTERNAL_SYSTEM_ERROR,
832*7c478bd9Sstevel@tonic-gate 		"cant_compute_hash",
833*7c478bd9Sstevel@tonic-gate 		new Object[] {e.getMessage()});
834*7c478bd9Sstevel@tonic-gate 	}
835*7c478bd9Sstevel@tonic-gate     }
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate     static private long getInt32(DataInputStream dis) throws IOException {
838*7c478bd9Sstevel@tonic-gate 	byte[] bytes = new byte[4];
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 	dis.readFully(bytes, 0, 4);
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	long a = (long)(bytes[0] & 0xFF);
843*7c478bd9Sstevel@tonic-gate 	long b = (long)(bytes[1] & 0xFF);
844*7c478bd9Sstevel@tonic-gate 	long c = (long)(bytes[2] & 0xFF);
845*7c478bd9Sstevel@tonic-gate 	long d = (long)(bytes[3] & 0xFF);
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	long i = a << 24;
848*7c478bd9Sstevel@tonic-gate 	i += b << 16;
849*7c478bd9Sstevel@tonic-gate 	i += c << 8;
850*7c478bd9Sstevel@tonic-gate 	i += d;
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 	return i;
853*7c478bd9Sstevel@tonic-gate     }
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate     static private void putInt32(long i, ByteArrayOutputStream baos) {
856*7c478bd9Sstevel@tonic-gate 	baos.write((byte) ((i >> 24) & 0xFF));
857*7c478bd9Sstevel@tonic-gate 	baos.write((byte) ((i >> 16) & 0xFF));
858*7c478bd9Sstevel@tonic-gate 	baos.write((byte) ((i >> 8)  & 0xFF));
859*7c478bd9Sstevel@tonic-gate 	baos.write((byte) (i & 0XFF));
860*7c478bd9Sstevel@tonic-gate     }
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate     /**
863*7c478bd9Sstevel@tonic-gate      * Determines if this process' SPI configuration allows
864*7c478bd9Sstevel@tonic-gate      * messages signed by 'cert' to be verified. This method
865*7c478bd9Sstevel@tonic-gate      * also verifies and validates 'cert's cert chain.
866*7c478bd9Sstevel@tonic-gate      */
867*7c478bd9Sstevel@tonic-gate     private void checkSPIs(X509Certificate cert, KeyStore ks)
868*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, GeneralSecurityException {
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate 	// get the list of configured SPIs
871*7c478bd9Sstevel@tonic-gate 	String conf_spis = System.getProperty("sun.net.slp.SPIs");
872*7c478bd9Sstevel@tonic-gate 	if (conf_spis == null) {
873*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
874*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
875*7c478bd9Sstevel@tonic-gate 		"no_spis_configured", new Object[0]);
876*7c478bd9Sstevel@tonic-gate 	}
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 	// Get cert chain
879*7c478bd9Sstevel@tonic-gate 	java.security.cert.Certificate[] chain =
880*7c478bd9Sstevel@tonic-gate 	    ks.getCertificateChain(cert.getSubjectDN().toString());
881*7c478bd9Sstevel@tonic-gate 	if (chain == null) {
882*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
883*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
884*7c478bd9Sstevel@tonic-gate 		"no_cert_chain",
885*7c478bd9Sstevel@tonic-gate 		new Object[] {cert.getSubjectDN().toString()});
886*7c478bd9Sstevel@tonic-gate 	}
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate 	// validate all links in chain
889*7c478bd9Sstevel@tonic-gate 	int i = 0;
890*7c478bd9Sstevel@tonic-gate 	try {
891*7c478bd9Sstevel@tonic-gate 	    // Add cert's own subjec to equiv set
892*7c478bd9Sstevel@tonic-gate 	    eqSet.add(((X509Certificate)chain[0]).getSubjectDN());
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	    for (i = 1; i < chain.length; i++) {
895*7c478bd9Sstevel@tonic-gate 		((X509Certificate)chain[i]).checkValidity();
896*7c478bd9Sstevel@tonic-gate 		chain[i-1].verify(chain[i].getPublicKey(), "SunAMI");
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 		// OK, so add to equivalency set
899*7c478bd9Sstevel@tonic-gate 		eqSet.add(((X509Certificate)chain[i]).getSubjectDN());
900*7c478bd9Sstevel@tonic-gate 	    }
901*7c478bd9Sstevel@tonic-gate 	} catch (ClassCastException e) {
902*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
903*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
904*7c478bd9Sstevel@tonic-gate 		"not_x509cert",
905*7c478bd9Sstevel@tonic-gate 		new Object[] { chain[i].getType(), e.getMessage() });
906*7c478bd9Sstevel@tonic-gate 	}
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	if (configuredToVerify(chain, conf_spis, ks)) {
909*7c478bd9Sstevel@tonic-gate 	    return;
910*7c478bd9Sstevel@tonic-gate 	}
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	// if we get here, no SPIs matched, so the authentication fails
913*7c478bd9Sstevel@tonic-gate 	throw new ServiceLocationException(
914*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
915*7c478bd9Sstevel@tonic-gate 		"cant_match_spis",
916*7c478bd9Sstevel@tonic-gate 		new Object[] {cert.getSubjectDN().toString(), ""});
917*7c478bd9Sstevel@tonic-gate     }
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate     /**
920*7c478bd9Sstevel@tonic-gate      * Determines if, given a set of SPIs 'conf_spis', we can
921*7c478bd9Sstevel@tonic-gate      * verify a message signed by the Principal named by 'cert'.
922*7c478bd9Sstevel@tonic-gate      */
923*7c478bd9Sstevel@tonic-gate     static private boolean configuredToVerify(
924*7c478bd9Sstevel@tonic-gate 				java.security.cert.Certificate[] chain,
925*7c478bd9Sstevel@tonic-gate 				String conf_spis,
926*7c478bd9Sstevel@tonic-gate 				KeyStore ks) {
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	StringTokenizer stk = new StringTokenizer(conf_spis, ",");
929*7c478bd9Sstevel@tonic-gate 	while (stk.hasMoreTokens()) {
930*7c478bd9Sstevel@tonic-gate 	    String spi;
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	    try {
933*7c478bd9Sstevel@tonic-gate 		spi = stk.nextToken();
934*7c478bd9Sstevel@tonic-gate 	    } catch (NoSuchElementException e) {
935*7c478bd9Sstevel@tonic-gate 		break;
936*7c478bd9Sstevel@tonic-gate 	    }
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	    // get CA cert to get CA Principal
939*7c478bd9Sstevel@tonic-gate 	    Principal ca;
940*7c478bd9Sstevel@tonic-gate 	    try {
941*7c478bd9Sstevel@tonic-gate 		X509Certificate cacert = getCert(spi, ks);
942*7c478bd9Sstevel@tonic-gate 		ca = cacert.getSubjectDN();
943*7c478bd9Sstevel@tonic-gate 	    } catch (ServiceLocationException e) {
944*7c478bd9Sstevel@tonic-gate 		SLPConfig.getSLPConfig().writeLog(
945*7c478bd9Sstevel@tonic-gate 			"cant_process_spi",
946*7c478bd9Sstevel@tonic-gate 			new Object[] {spi, e.getMessage()});
947*7c478bd9Sstevel@tonic-gate 		continue;
948*7c478bd9Sstevel@tonic-gate 	    }
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	    if (onCertChain(ca, chain)) {
951*7c478bd9Sstevel@tonic-gate 		return true;
952*7c478bd9Sstevel@tonic-gate 	    }
953*7c478bd9Sstevel@tonic-gate 	}
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	return false;
956*7c478bd9Sstevel@tonic-gate     }
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate     /**
959*7c478bd9Sstevel@tonic-gate      * Determines if sub if equivalent to ca by getting sub's cert
960*7c478bd9Sstevel@tonic-gate      * chain and walking the chain looking for ca.
961*7c478bd9Sstevel@tonic-gate      * This routine does not verify the cert chain.
962*7c478bd9Sstevel@tonic-gate      */
963*7c478bd9Sstevel@tonic-gate     private static boolean onCertChain(String sub, Principal ca)
964*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	java.security.cert.Certificate[] chain;
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 	ServiceLocationException ex = new ServiceLocationException(
969*7c478bd9Sstevel@tonic-gate 			ServiceLocationException.AUTHENTICATION_UNKNOWN,
970*7c478bd9Sstevel@tonic-gate 			"no_cert_chain",
971*7c478bd9Sstevel@tonic-gate 			new Object[] {sub});
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	try {
974*7c478bd9Sstevel@tonic-gate 	    // Get cert keystore
975*7c478bd9Sstevel@tonic-gate 	    KeyStore ks = getKeyStore();
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	    // Get cert chain for subject
978*7c478bd9Sstevel@tonic-gate 	    chain = ks.getCertificateChain(sub);
979*7c478bd9Sstevel@tonic-gate 	} catch (KeyStoreException e) {
980*7c478bd9Sstevel@tonic-gate 	    throw ex;
981*7c478bd9Sstevel@tonic-gate 	}
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 	if (chain == null) {
984*7c478bd9Sstevel@tonic-gate 	    throw ex;
985*7c478bd9Sstevel@tonic-gate 	}
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	// walk the cert chain
988*7c478bd9Sstevel@tonic-gate 	return onCertChain(ca, chain);
989*7c478bd9Sstevel@tonic-gate     }
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate     /**
992*7c478bd9Sstevel@tonic-gate      * Operates the same as above, but rather than getting the cert
993*7c478bd9Sstevel@tonic-gate      * chain for sub, uses a given cert chain.
994*7c478bd9Sstevel@tonic-gate      */
995*7c478bd9Sstevel@tonic-gate     private static boolean onCertChain(Principal ca,
996*7c478bd9Sstevel@tonic-gate 				       java.security.cert.Certificate[] chain)
997*7c478bd9Sstevel@tonic-gate     {
998*7c478bd9Sstevel@tonic-gate 	// walk the cert chain
999*7c478bd9Sstevel@tonic-gate 	for (int i = 0; i < chain.length; i++) {
1000*7c478bd9Sstevel@tonic-gate 	    Principal sub = ((X509Certificate)chain[i]).getSubjectDN();
1001*7c478bd9Sstevel@tonic-gate 	    if (ca.equals(sub)) {
1002*7c478bd9Sstevel@tonic-gate 		return true;
1003*7c478bd9Sstevel@tonic-gate 	    }
1004*7c478bd9Sstevel@tonic-gate 	}
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate 	return false;
1007*7c478bd9Sstevel@tonic-gate     }
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate     /**
1010*7c478bd9Sstevel@tonic-gate      * Returns true if someDN is in this AuthBlock's equivalence set.
1011*7c478bd9Sstevel@tonic-gate      */
1012*7c478bd9Sstevel@tonic-gate     private boolean inEqSet(Principal someDN) {
1013*7c478bd9Sstevel@tonic-gate 	return eqSet.contains(someDN);
1014*7c478bd9Sstevel@tonic-gate     }
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate     /**
1017*7c478bd9Sstevel@tonic-gate      * Retrieves from the KeyStore 'ks' the X509Certificate named
1018*7c478bd9Sstevel@tonic-gate      * by DN.
1019*7c478bd9Sstevel@tonic-gate      */
1020*7c478bd9Sstevel@tonic-gate     static private X509Certificate getCert(String DN, KeyStore ks)
1021*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	X509Certificate cert = null;
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	// Unescape DN
1026*7c478bd9Sstevel@tonic-gate 	try {
1027*7c478bd9Sstevel@tonic-gate 	    DN = ServiceLocationAttribute.unescapeAttributeString(DN, false);
1028*7c478bd9Sstevel@tonic-gate 	} catch (ServiceLocationException e) {
1029*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
1030*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.PARSE_ERROR,
1031*7c478bd9Sstevel@tonic-gate 		"spi_parse_error",
1032*7c478bd9Sstevel@tonic-gate 		new Object[] {DN, e.getMessage()});
1033*7c478bd9Sstevel@tonic-gate 	}
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	try {
1036*7c478bd9Sstevel@tonic-gate 	    cert = (X509Certificate)ks.getCertificate(DN);
1037*7c478bd9Sstevel@tonic-gate 	} catch (ClassCastException e) {
1038*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
1039*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
1040*7c478bd9Sstevel@tonic-gate 		"not_x509cert",
1041*7c478bd9Sstevel@tonic-gate 		new Object[] {cert.getType(), e.getMessage()});
1042*7c478bd9Sstevel@tonic-gate 	} catch (KeyStoreException e) {
1043*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
1044*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
1045*7c478bd9Sstevel@tonic-gate 		"no_cert",
1046*7c478bd9Sstevel@tonic-gate 		new Object[] {DN, e.getMessage()});
1047*7c478bd9Sstevel@tonic-gate 	}
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 	if (cert == null) {
1050*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
1051*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
1052*7c478bd9Sstevel@tonic-gate 		"no_cert",
1053*7c478bd9Sstevel@tonic-gate 		new Object[] {DN, "" });
1054*7c478bd9Sstevel@tonic-gate 	}
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate 	return cert;
1057*7c478bd9Sstevel@tonic-gate     }
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate     /**
1060*7c478bd9Sstevel@tonic-gate      * Gets a handle to the trusted key package for this process.
1061*7c478bd9Sstevel@tonic-gate      */
1062*7c478bd9Sstevel@tonic-gate     static private synchronized KeyStore getKeyPkg()
1063*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 	if (keypkg != null) {
1066*7c478bd9Sstevel@tonic-gate 	    return keypkg;
1067*7c478bd9Sstevel@tonic-gate 	}
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	/* else load key store */
1070*7c478bd9Sstevel@tonic-gate 	try {
1071*7c478bd9Sstevel@tonic-gate 	    keypkg = KeyStore.getInstance("amiks", "SunAMI");
1072*7c478bd9Sstevel@tonic-gate 	    keypkg.load(null, null);
1073*7c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
1074*7c478bd9Sstevel@tonic-gate 	    throw new ServiceLocationException(
1075*7c478bd9Sstevel@tonic-gate 		ServiceLocationException.AUTHENTICATION_FAILED,
1076*7c478bd9Sstevel@tonic-gate 		"no_keystore",
1077*7c478bd9Sstevel@tonic-gate 		new Object[] {e.getMessage()});
1078*7c478bd9Sstevel@tonic-gate 	}
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate 	return keypkg;
1081*7c478bd9Sstevel@tonic-gate     }
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate     /**
1084*7c478bd9Sstevel@tonic-gate      * Gets a handle to a certificate repository.
1085*7c478bd9Sstevel@tonic-gate      */
1086*7c478bd9Sstevel@tonic-gate     static private synchronized KeyStore getKeyStore()
1087*7c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 	if (keystore != null) {
1090*7c478bd9Sstevel@tonic-gate 	    return keystore;
1091*7c478bd9Sstevel@tonic-gate 	}
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate 	try {
1094*7c478bd9Sstevel@tonic-gate 	    keystore = KeyStore.getInstance("amicerts", "SunAMI");
1095*7c478bd9Sstevel@tonic-gate 	    keystore.load(null, null);
1096*7c478bd9Sstevel@tonic-gate 	} catch (Exception e) {
1097*7c478bd9Sstevel@tonic-gate 	    throw
1098*7c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1099*7c478bd9Sstevel@tonic-gate 			ServiceLocationException.AUTHENTICATION_FAILED,
1100*7c478bd9Sstevel@tonic-gate 			"no_keystore",
1101*7c478bd9Sstevel@tonic-gate 			new Object[] {e.getMessage()});
1102*7c478bd9Sstevel@tonic-gate 	}
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate 	return keystore;
1105*7c478bd9Sstevel@tonic-gate     }
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate     public String toString() {
1108*7c478bd9Sstevel@tonic-gate 	return  "SPI=``" + spi + "''\n" +
1109*7c478bd9Sstevel@tonic-gate 		"                BSD=``" + bsd + "''\n" +
1110*7c478bd9Sstevel@tonic-gate 		"                timeStamp=``" + timeStamp + "''\n" +
1111*7c478bd9Sstevel@tonic-gate 		"                AuthBlock bytes=" + abLength + " bytes\n";
1112*7c478bd9Sstevel@tonic-gate     }
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate     // Instance variables
1116*7c478bd9Sstevel@tonic-gate     int bsd;
1117*7c478bd9Sstevel@tonic-gate     String spi;
1118*7c478bd9Sstevel@tonic-gate     Object[] message;
1119*7c478bd9Sstevel@tonic-gate     int lifetime;	// need both: lifetime is for optimization,
1120*7c478bd9Sstevel@tonic-gate     long timeStamp;	// timeStamp is needed to compute the hash
1121*7c478bd9Sstevel@tonic-gate     SrvLocHeader hdr;
1122*7c478bd9Sstevel@tonic-gate     Signature sig;
1123*7c478bd9Sstevel@tonic-gate     int abLength;
1124*7c478bd9Sstevel@tonic-gate     byte[] abBytes;
1125*7c478bd9Sstevel@tonic-gate     byte[] spiBytes;
1126*7c478bd9Sstevel@tonic-gate     HashSet eqSet;	// built only during authblock verification
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate     // cached per process
1129*7c478bd9Sstevel@tonic-gate     static private KeyStore keystore;	// Certificate repository
1130*7c478bd9Sstevel@tonic-gate     static private KeyStore keypkg;	// My own keypkg
1131*7c478bd9Sstevel@tonic-gate }
1132