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