/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * ident "%Z%%M% %I% %E% SMI" * * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. * */ package com.sun.slp; import java.util.*; import java.io.*; import java.security.*; import java.security.cert.*; /** * The AuthBlock class models both the client and server side * authentication blocks. *

* AuthBlocks are agnostic as to which components from a given * message should be used in authentication. Thus each message * must provide the correct components in the correct order. *

* These components are passed via Object[]s. The Object[] elements * should be in externalized form, and should be ordered as stated * in the protocol specification for auth blocks. AuthBlocks will * add the externalized SPI string before the Object[] and the * externalized timestamp after the vector. *

* The AuthBlock class provides a number of static convenience * methods which operate on sets of AuthBlocks. The sets of * AuthBlocks are stored in Hashtables, keyed by SPIs. */ class AuthBlock { static private String SPI_PROPERTY = "sun.net.slp.SPIs"; /** * A convenience method for creating a set of auth blocks * from internal data structures. * * @param message The ordered components of the SLP message * over which the signature should be computed, * in externalized (byte[]) form. * @param lifetime The lifetime for this message, in seconds. * @return A Hashtable of AuthBlocks, one for each SPI, null if no * SPIs have been configured. * @exception ServiceLocationException If a key management or crypto * algorithm provider cannot be * instantiated, a SYSTEM_ERROR exception * is thrown. * @exception IllegalArgumentException If any of the parameters are null * or empty. */ static Hashtable makeAuthBlocks(Object[] message, int lifetime) throws ServiceLocationException, IllegalArgumentException { Hashtable spis = getSignAs(); if (spis == null) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "cant_sign", new Object[0]); } Hashtable blocks = new Hashtable(); Enumeration spisEnum = spis.keys(); while (spisEnum.hasMoreElements()) { String spi = (String) spisEnum.nextElement(); int bsd = ((Integer)(spis.get(spi))).intValue(); blocks.put(spi, new AuthBlock(message, spi, bsd, lifetime)); } return blocks; } /** * A convenience method which creates a Hashtable of auth blocks * from an input stream. * * @param hdr Header of message being parsed out. * @param message The ordered components of the SLP message * over which the signature should have been computed, * in externalized (byte[]) form. * @param dis Input stream with the auth block bytes queued up as the * next thing. * @param nBlocks Number of auth blocks to read. * @return A Hashtable of AuthBlocks. * @exception ServiceLocationException If anything goes wrong during * parsing. If nBlocks is 0, the * error code is AUTHENTICATION_ABSENT. * @exception IllegalArgumentException If any of the parameters are null * or empty. * @exception IOException If DataInputStream throws it. */ static Hashtable makeAuthBlocks(SrvLocHeader hdr, Object[] message, DataInputStream dis, byte nBlocks) throws ServiceLocationException, IllegalArgumentException, IOException { Hashtable blocks = new Hashtable(); for (byte cnt = 0; cnt < nBlocks; cnt++) { AuthBlock ab = new AuthBlock(hdr, message, dis); blocks.put(ab.getSPI(), ab); } return blocks; } /** * A convenience method which verifies all auth blocks in the * input Hashtable. * * @param authBlocks A Hashtable containing AuthBlocks. * @exception ServiceLocationException Thrown if authentication fails, * with the error code * ServiceLocationException.AUTHENTICATION_FAILED. If any * other error occurs during authentication, the * error code is ServiceLocationException.SYSTEM_ERROR. * If the signature hasn't been calculated the * authentication fails. * @exception IllegalArgumentException If authBlocks is null or empty. */ static void verifyAll(Hashtable authBlocks) throws ServiceLocationException, IllegalArgumentException { ensureNonEmpty(authBlocks, "authBlocks"); Enumeration blocks = authBlocks.elements(); while (blocks.hasMoreElements()) { AuthBlock ab = (AuthBlock) blocks.nextElement(); ab.verify(); } } /** * A convenience method which finds the shortest lifetime in a * set of AuthBlocks. * * @param authBlocks A Hashtable containing AuthBlocks. * @return The shortest lifetime found. * @exception IllegalArgumentException If authBlocks is null or empty. */ static int getShortestLifetime(Hashtable authBlocks) throws IllegalArgumentException { ensureNonEmpty(authBlocks, "authBlocks"); Enumeration blocks = authBlocks.elements(); int lifetime = Integer.MAX_VALUE; while (blocks.hasMoreElements()) { AuthBlock ab = (AuthBlock) blocks.nextElement(); int abLife = ab.getLifetime(); lifetime = (lifetime < abLife) ? lifetime : abLife; } return lifetime; } /** * A convenience method which externalizes a set of AuthBlocks * into a ByteArrayOutputStream. The number of blocks is NOT * written onto the stream. * * @param hdr Header of message being externalized. * @param authBlocks A Hashtable containing AuthBlocks. * @param baos The output stream into which to write. * @exception ServiceLocationException Thrown if an error occurs during * output, with PARSE_ERROR error code. * @exception IllegalArgumentException If any parameters are null, or * if authBlocks is empty. */ static void externalizeAll(SrvLocHeader hdr, Hashtable authBlocks, ByteArrayOutputStream baos) throws ServiceLocationException, IllegalArgumentException { ensureNonEmpty(authBlocks, "authBlocks"); Enumeration blocks = authBlocks.elements(); while (blocks.hasMoreElements()) { AuthBlock ab = (AuthBlock) blocks.nextElement(); ab.externalize(hdr, baos); } } /** * Returns the message parts obtained from the AuthBlock contructor. * The Object[] will not have been altered. Note that all AuthBlocks * contain the same message Object[] Object. * * @param authBlocks A Hashtable containing AuthBlocks. * @return This auth block's message components Object[]. * @exception IllegalArgumentException If authBlocks is null or empty. */ static Object[] getContents(Hashtable authBlocks) throws IllegalArgumentException { ensureNonEmpty(authBlocks, "authBlocks"); Enumeration blocks = authBlocks.elements(); AuthBlock ab = (AuthBlock) blocks.nextElement(); return ab.getMessageParts(); } /** * Creates a String describing all auth blocks in authBlocks. * We dont't use toString() since that would get Hashtable.toString(), * and we can format it a little prettier. * * @param authBlocks A Hashtable containing AuthBlocks. * @return A String description of all AuthBlocks in this Hashtable */ static String desc(Hashtable authBlocks) { if (authBlocks == null) { return "null"; } Enumeration blocks = authBlocks.elements(); int size = authBlocks.size(); String desc = size == 1 ? "1 Auth Block:\n" : size + " Auth Blocks:\n"; int cnt = 0; while (blocks.hasMoreElements()) { AuthBlock ab = (AuthBlock) blocks.nextElement(); desc = desc + " " + (cnt++) + ": " + ab.toString(); } return desc; } /** * Returns the list of SPIs configured with this 'prop', or null * if the property hasn't been set. */ static LinkedList getSPIList(String prop) { String spiProp = System.getProperty(prop); if (spiProp == null) { return null; } return commaSeparatedListToLinkedList(spiProp); } /** * Converts a comma-separaterd list in a String to a LinkedList. */ static LinkedList commaSeparatedListToLinkedList(String listStr) { StringTokenizer stk_comma = new StringTokenizer(listStr, ","); LinkedList answer = new LinkedList(); while (stk_comma.hasMoreTokens()) { String spi = stk_comma.nextToken(); answer.add(spi); } return answer; } /** * Returns true if this principal is someDH, or if this principal's * cert has been signed by someDN. */ static boolean canSignAs(String someDN) throws ServiceLocationException { X509Certificate myCert = getSignAsCert(); if (myCert == null) { return false; } KeyStore ks = getKeyStore(); if (ks == null) { return false; } X509Certificate cert = getCert(someDN, ks); return onCertChain( myCert.getSubjectDN().toString(), cert.getSubjectDN()); } /** * Checks if caDN is in ab's equivalency set, i.e. if caDN * is in ab's cert chain. */ static boolean checkEquiv(String caDN, AuthBlock ab) { // Get cert for input DN X509Certificate caCert; try { KeyStore ks = getKeyStore(); caCert = getCert(caDN, ks); } catch (Exception e) { SLPConfig.getSLPConfig().writeLog( "cant_get_equivalency", new Object[] {caDN, e.getMessage()}); return false; } return ab.inEqSet(caCert.getSubjectDN()); } /** * Filters out from auths all auth blocks which have not been * signed by DNs equivalent to caDN. */ static AuthBlock getEquivalentAuth(String caDN, Hashtable authBlocks) { if (authBlocks.size() == 0) { return null; } // Get cert for input DN X509Certificate caCert; try { KeyStore ks = getKeyStore(); caCert = getCert(caDN, ks); } catch (Exception e) { SLPConfig.getSLPConfig().writeLog( "cant_get_equivalency", new Object[] { caDN, e.getMessage()}); return null; } Enumeration blocks = authBlocks.elements(); while (blocks.hasMoreElements()) { AuthBlock ab = (AuthBlock) blocks.nextElement(); if (ab.inEqSet(caCert.getSubjectDN())) { return ab; } } return null; } /** * Gets a list of signing identities. Returns a Hashtable of * which the keys are SPI strings (DNs) and the values * are BSD Integers. */ static Hashtable getSignAs() throws ServiceLocationException { X509Certificate cert = getSignAsCert(); Hashtable answer = new Hashtable(); if (cert == null) { return null; } /* derive DN from alias */ String DN = cert.getSubjectDN().toString(); String e_DN = null; // escape DN try { e_DN = ServiceLocationAttribute.escapeAttributeString(DN, false); } catch (ServiceLocationException e) { // Shouldn't get here if badTag == false e_DN = DN; } DN = e_DN; String alg = cert.getPublicKey().getAlgorithm(); int ibsd; if (alg.equals("DSA")) { ibsd = 2; } else if (alg.equals("RSA")) { ibsd = 1; } else { SLPConfig.getSLPConfig().writeLog("bad_alg_for_alias", new Object[] {alg}); return null; } answer.put(DN, new Integer(ibsd)); return answer; } /** * Returns the cert corresponding to our signing alias. * @@@ change this when AMI goes in to use private AMI interface. */ static X509Certificate getSignAsCert() throws ServiceLocationException { String spiProp = System.getProperty("sun.net.slp.signAs"); if (spiProp == null) { SLPConfig.getSLPConfig().writeLog( "no_spis_given", new Object[0]); return null; } /* load key store */ KeyStore ks = getKeyPkg(); StringTokenizer stk_comma = new StringTokenizer(spiProp, ","); X509Certificate cert = null; // Can only sign with one alias, so ignore any extras if (stk_comma.hasMoreTokens()) { String alias = stk_comma.nextToken(); /* get keypkg for this alias */ cert = getCert(alias, ks); } return cert; } /** * Creates a new AuthBlock based on the SPI and message parts. * * @param message The ordered components of the SLP message * over which the signature should be computed, * in externalized (byte[]) form. * @param spi The SLP SPI for which to create the auth block. * @param lifetime The lifetime for this message, in seconds. * @exception ServiceLocationException If a key management or crypto * algorithm provider cannot be * instantiated, a SYSTEM_ERROR exception * is thrown. * @exception IllegalArgumentException If any of the parameters are null * or empty. */ AuthBlock(Object[] message, String spi, int bsd, int lifetime) throws ServiceLocationException, IllegalArgumentException { ensureNonEmpty(message, "message"); Assert.nonNullParameter(spi, "spi"); // init crypto provider associated with bsd this.bsd = bsd; getSecurityProvider(bsd); this.message = message; this.spi = spi; this.lifetime = lifetime; this.timeStamp = SLPConfig.currentSLPTime() + lifetime; // Create the signature: create and sign the hash try { // @@@ how to sign for different aliases? sig.initSign(null); computeHash(); abBytes = sig.sign(); } catch (InvalidKeyException e) { // @@@ will change for AMI SLPConfig conf = SLPConfig.getSLPConfig(); throw new IllegalArgumentException( conf.formatMessage( "cant_sign_for_spi", new Object[] { spi, e.getMessage() })); } catch (SignatureException e) { SLPConfig conf = SLPConfig.getSLPConfig(); throw new IllegalArgumentException( conf.formatMessage( "cant_sign_for_spi", new Object[] { spi, e.getMessage() })); } // calculate the length abLength = 2 + // bsd 2 + // length 4 + // timestamp spiBytes.length + // externalized SPI string, with length abBytes.length; // structured auth block } /** * Creates a new AuthBlock from an input stream. * * @param hdr The header of the message being parsed. * @param message The ordered components of the SLP message * over which the signature should have been computed, * in externalized (byte[]) form. * @param dis Input stream with the auth block bytes queued up as the * next thing. * @exception ServiceLocationException If anything goes wrong during * parsing. If nBlocks is 0, the * error code is AUTHENTICATION_ABSENT. * @exception IllegalArgumentException If any of the parameters are null * or empty. * @exception IOException If DataInputStream throws it. */ AuthBlock(SrvLocHeader hdr, Object[] message, DataInputStream dis) throws ServiceLocationException, IllegalArgumentException, IOException { Assert.nonNullParameter(hdr, "hdr"); ensureNonEmpty(message, "message"); Assert.nonNullParameter(dis, "dis"); this.message = message; this.eqSet = new HashSet(); // parse in the auth block from the input stream; // first get the BSD and length bsd = hdr.getInt(dis); abLength = hdr.getInt(dis); int pos = 4; // bsd and length have already been consumed // get the timestamp timeStamp = getInt32(dis); pos += 4; hdr.nbytes += 4; // get the SPI StringBuffer buf = new StringBuffer(); hdr.getString(buf, dis); spi = buf.toString(); if (spi.length() == 0) { throw new ServiceLocationException( ServiceLocationException.PARSE_ERROR, "no_spi_string", new Object[0]); } pos += (2 + spi.length()); // get the structured auth block abBytes = new byte[abLength - pos]; dis.readFully(abBytes, 0, abLength - pos); hdr.nbytes += abBytes.length; // calculate remaining lifetime from timestamp long time = timeStamp - SLPConfig.currentSLPTime(); time = time <= Integer.MAX_VALUE ? time : 0; // no crazy values lifetime = (int) time; lifetime = lifetime < 0 ? 0 : lifetime; // Initialize the crypto provider getSecurityProvider(bsd); } /** * Gets the size of this auth block, after externalization, in bytes. * * @return The number of bytes in this auth block. */ int nBytes() { return abLength; } /** * Returns the message parts obtained from the AuthBlock contructor. * The Object[] will not have been altered. * * @return This auth block's message components Object[]. */ Object[] getMessageParts() { return message; } /** * Verifies the signature on this auth block. * * @exception ServiceLocationException Thrown if authentication fails, * with the error code * ServiceLocationException.AUTHENTICATION_FAILED. If any * other error occurs during authentication, the * error code is ServiceLocationException.SYSTEM_ERROR. * If the signature hasn't been calculated, the * fails. */ void verify() throws ServiceLocationException { // Load the keystore KeyStore ks = null; try { ks = KeyStore.getInstance("amicerts", "SunAMI"); ks.load(null, null); } catch (Exception e) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "no_keystore", new Object[] {e.getMessage()}); } // Unescape the SPI for cleaner logging String u_DN = null; try { u_DN = ServiceLocationAttribute.unescapeAttributeString(spi, false); } catch (ServiceLocationException e) { u_DN = spi; } // get cert for this spi X509Certificate cert = getCert(spi, ks); // check cert validity try { cert.checkValidity(); } catch (CertificateException e) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "invalid_cert", new Object[] {u_DN, e.getMessage()}); } // check the lifetime if (lifetime == 0) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "timestamp_failure", new Object[] {u_DN}); } // make sure this SPI matches up with configured SPIs try { checkSPIs(cert, ks); } catch (GeneralSecurityException e) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "cant_match_spis", new Object[] {cert.getSubjectDN(), e.getMessage()}); } // check the signature try { sig.initVerify(cert.getPublicKey()); } catch (InvalidKeyException ex) { throw new ServiceLocationException( ServiceLocationException.INTERNAL_SYSTEM_ERROR, "init_verify_failure", new Object[] { u_DN, ex.getMessage()}); } computeHash(); ServiceLocationException vex = new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "verify_failure", new Object[] {u_DN}); try { if (!sig.verify(abBytes)) throw vex; } catch (SignatureException ex) { throw vex; } } /** * Convert the auth block into its on-the-wire format. * * @param hdr The header of the message being parsed out. * @param baos The output stream into which to write. * @exception ServiceLocationException Thrown if an error occurs during * output, with PARSE_ERROR error code. * @exception IllegalArgumentException If any baos is null. */ void externalize(SrvLocHeader hdr, ByteArrayOutputStream baos) throws ServiceLocationException, IllegalArgumentException { Assert.nonNullParameter(hdr, "hdr"); Assert.nonNullParameter(baos, "baos"); // Lay out the auth block, starting with the BSD hdr.putInt(bsd, baos); // write out the length hdr.putInt(abLength, baos); // calculate and write out the timestamp putInt32(timeStamp, baos); hdr.nbytes += 4; // write the SPI string hdr.putString(spi, baos); // Finish by writting the structured auth block baos.write(abBytes, 0, abBytes.length); hdr.nbytes += abBytes.length; } /** * Returns the SPI associated with this auth block. * * @return The SLP SPI for this auth block. */ String getSPI() { return spi; } /** * Returns the lifetime computed from this auth block. * * @return The lifetime from this auth block. */ int getLifetime() { return lifetime; } /** * Given a BSD, sets this AuthBlock's Signature to the * right algorithm. */ private void getSecurityProvider(int bsd) throws ServiceLocationException { String algo = "Unknown BSD"; try { if (bsd == 2) { // get DSA/SHA1 provider algo = "DSA"; sig = Signature.getInstance("SHA/DSA", "SunAMI"); return; } else if (bsd == 1) { algo = "MD5/RSA"; sig = Signature.getInstance("MD5/RSA", "SunAMI"); return; } else if (bsd == 3) { algo = "Keyed HMAC with MD5"; } } catch (GeneralSecurityException e) { // system error -- no such provider throw new ServiceLocationException( ServiceLocationException.INTERNAL_SYSTEM_ERROR, "cant_get_security_provider", new Object[] { new Integer(bsd), algo, e.getMessage()}); } // Unknown or unsupported BSD throw new ServiceLocationException( ServiceLocationException.INTERNAL_SYSTEM_ERROR, "cant_get_security_provider", new Object[] { new Integer(bsd), algo, "Unknown or unsupported BSD"}); } /** * throws an IllegalArgumentException if v is null or empty. * v can be either a Hashtable or a Object[]. */ static private void ensureNonEmpty(Object v, String param) throws IllegalArgumentException { int size = 0; if (v != null) { if (v instanceof Object[]) { size = ((Object[]) v).length; } else { // this will force a class cast exception if not a Hashtable size = ((Hashtable) v).size(); } } if (v == null || size == 0) { SLPConfig conf = SLPConfig.getSLPConfig(); String msg = conf.formatMessage("null_or_empty_vector", new Object[] {param}); throw new IllegalArgumentException(msg); } } /** * Computes a hash over the SPI String, message componenets, * and timstamp. Which hash is used depends on which crypto * provider was installed. * * This method assumes that the class variables spi, sig, * message, and timeStamp have all been initialized. As a side * effect, it places the externalized SPI String into spiBytes. */ private void computeHash() throws ServiceLocationException { try { // get the SPI String bytes ByteArrayOutputStream baosT = new ByteArrayOutputStream(); SrvLocHeader.putStringField(spi, baosT, Defaults.UTF8); spiBytes = baosT.toByteArray(); sig.update(spiBytes); // Add each message component int mSize = message.length; for (int i = 0; i < mSize; i++) { sig.update((byte[]) message[i]); } // end by adding the timestamp baosT = new ByteArrayOutputStream(); putInt32(timeStamp, baosT); sig.update(baosT.toByteArray()); } catch (SignatureException e) { throw new ServiceLocationException( ServiceLocationException.INTERNAL_SYSTEM_ERROR, "cant_compute_hash", new Object[] {e.getMessage()}); } } static private long getInt32(DataInputStream dis) throws IOException { byte[] bytes = new byte[4]; dis.readFully(bytes, 0, 4); long a = (long)(bytes[0] & 0xFF); long b = (long)(bytes[1] & 0xFF); long c = (long)(bytes[2] & 0xFF); long d = (long)(bytes[3] & 0xFF); long i = a << 24; i += b << 16; i += c << 8; i += d; return i; } static private void putInt32(long i, ByteArrayOutputStream baos) { baos.write((byte) ((i >> 24) & 0xFF)); baos.write((byte) ((i >> 16) & 0xFF)); baos.write((byte) ((i >> 8) & 0xFF)); baos.write((byte) (i & 0XFF)); } /** * Determines if this process' SPI configuration allows * messages signed by 'cert' to be verified. This method * also verifies and validates 'cert's cert chain. */ private void checkSPIs(X509Certificate cert, KeyStore ks) throws ServiceLocationException, GeneralSecurityException { // get the list of configured SPIs String conf_spis = System.getProperty("sun.net.slp.SPIs"); if (conf_spis == null) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "no_spis_configured", new Object[0]); } // Get cert chain java.security.cert.Certificate[] chain = ks.getCertificateChain(cert.getSubjectDN().toString()); if (chain == null) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "no_cert_chain", new Object[] {cert.getSubjectDN().toString()}); } // validate all links in chain int i = 0; try { // Add cert's own subjec to equiv set eqSet.add(((X509Certificate)chain[0]).getSubjectDN()); for (i = 1; i < chain.length; i++) { ((X509Certificate)chain[i]).checkValidity(); chain[i-1].verify(chain[i].getPublicKey(), "SunAMI"); // OK, so add to equivalency set eqSet.add(((X509Certificate)chain[i]).getSubjectDN()); } } catch (ClassCastException e) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "not_x509cert", new Object[] { chain[i].getType(), e.getMessage() }); } if (configuredToVerify(chain, conf_spis, ks)) { return; } // if we get here, no SPIs matched, so the authentication fails throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "cant_match_spis", new Object[] {cert.getSubjectDN().toString(), ""}); } /** * Determines if, given a set of SPIs 'conf_spis', we can * verify a message signed by the Principal named by 'cert'. */ static private boolean configuredToVerify( java.security.cert.Certificate[] chain, String conf_spis, KeyStore ks) { StringTokenizer stk = new StringTokenizer(conf_spis, ","); while (stk.hasMoreTokens()) { String spi; try { spi = stk.nextToken(); } catch (NoSuchElementException e) { break; } // get CA cert to get CA Principal Principal ca; try { X509Certificate cacert = getCert(spi, ks); ca = cacert.getSubjectDN(); } catch (ServiceLocationException e) { SLPConfig.getSLPConfig().writeLog( "cant_process_spi", new Object[] {spi, e.getMessage()}); continue; } if (onCertChain(ca, chain)) { return true; } } return false; } /** * Determines if sub if equivalent to ca by getting sub's cert * chain and walking the chain looking for ca. * This routine does not verify the cert chain. */ private static boolean onCertChain(String sub, Principal ca) throws ServiceLocationException { java.security.cert.Certificate[] chain; ServiceLocationException ex = new ServiceLocationException( ServiceLocationException.AUTHENTICATION_UNKNOWN, "no_cert_chain", new Object[] {sub}); try { // Get cert keystore KeyStore ks = getKeyStore(); // Get cert chain for subject chain = ks.getCertificateChain(sub); } catch (KeyStoreException e) { throw ex; } if (chain == null) { throw ex; } // walk the cert chain return onCertChain(ca, chain); } /** * Operates the same as above, but rather than getting the cert * chain for sub, uses a given cert chain. */ private static boolean onCertChain(Principal ca, java.security.cert.Certificate[] chain) { // walk the cert chain for (int i = 0; i < chain.length; i++) { Principal sub = ((X509Certificate)chain[i]).getSubjectDN(); if (ca.equals(sub)) { return true; } } return false; } /** * Returns true if someDN is in this AuthBlock's equivalence set. */ private boolean inEqSet(Principal someDN) { return eqSet.contains(someDN); } /** * Retrieves from the KeyStore 'ks' the X509Certificate named * by DN. */ static private X509Certificate getCert(String DN, KeyStore ks) throws ServiceLocationException { X509Certificate cert = null; // Unescape DN try { DN = ServiceLocationAttribute.unescapeAttributeString(DN, false); } catch (ServiceLocationException e) { throw new ServiceLocationException( ServiceLocationException.PARSE_ERROR, "spi_parse_error", new Object[] {DN, e.getMessage()}); } try { cert = (X509Certificate)ks.getCertificate(DN); } catch (ClassCastException e) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "not_x509cert", new Object[] {cert.getType(), e.getMessage()}); } catch (KeyStoreException e) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "no_cert", new Object[] {DN, e.getMessage()}); } if (cert == null) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "no_cert", new Object[] {DN, "" }); } return cert; } /** * Gets a handle to the trusted key package for this process. */ static private synchronized KeyStore getKeyPkg() throws ServiceLocationException { if (keypkg != null) { return keypkg; } /* else load key store */ try { keypkg = KeyStore.getInstance("amiks", "SunAMI"); keypkg.load(null, null); } catch (Exception e) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "no_keystore", new Object[] {e.getMessage()}); } return keypkg; } /** * Gets a handle to a certificate repository. */ static private synchronized KeyStore getKeyStore() throws ServiceLocationException { if (keystore != null) { return keystore; } try { keystore = KeyStore.getInstance("amicerts", "SunAMI"); keystore.load(null, null); } catch (Exception e) { throw new ServiceLocationException( ServiceLocationException.AUTHENTICATION_FAILED, "no_keystore", new Object[] {e.getMessage()}); } return keystore; } public String toString() { return "SPI=``" + spi + "''\n" + " BSD=``" + bsd + "''\n" + " timeStamp=``" + timeStamp + "''\n" + " AuthBlock bytes=" + abLength + " bytes\n"; } // Instance variables int bsd; String spi; Object[] message; int lifetime; // need both: lifetime is for optimization, long timeStamp; // timeStamp is needed to compute the hash SrvLocHeader hdr; Signature sig; int abLength; byte[] abBytes; byte[] spiBytes; HashSet eqSet; // built only during authblock verification // cached per process static private KeyStore keystore; // Certificate repository static private KeyStore keypkg; // My own keypkg }