package com.sun.slp;
import java.util.*;
import java.io.*;
import java.security.*;
import java.security.cert.*;
class AuthBlock {
static private String SPI_PROPERTY = "sun.net.slp.SPIs";
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;
}
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;
}
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();
}
}
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;
}
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);
}
}
static Object[] getContents(Hashtable authBlocks)
throws IllegalArgumentException {
ensureNonEmpty(authBlocks, "authBlocks");
Enumeration blocks = authBlocks.elements();
AuthBlock ab = (AuthBlock) blocks.nextElement();
return ab.getMessageParts();
}
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;
}
static LinkedList getSPIList(String prop) {
String spiProp = System.getProperty(prop);
if (spiProp == null) {
return null;
}
return commaSeparatedListToLinkedList(spiProp);
}
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;
}
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());
}
static boolean checkEquiv(String caDN, AuthBlock ab) {
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());
}
static AuthBlock getEquivalentAuth(String caDN, Hashtable authBlocks) {
if (authBlocks.size() == 0) {
return null;
}
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;
}
static Hashtable getSignAs() throws ServiceLocationException {
X509Certificate cert = getSignAsCert();
Hashtable answer = new Hashtable();
if (cert == null) {
return null;
}
String DN = cert.getSubjectDN().toString();
String e_DN = null;
try {
e_DN = ServiceLocationAttribute.escapeAttributeString(DN, false);
} catch (ServiceLocationException e) {
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, Integer.valueOf(ibsd));
return answer;
}
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;
}
KeyStore ks = getKeyPkg();
StringTokenizer stk_comma = new StringTokenizer(spiProp, ",");
X509Certificate cert = null;
if (stk_comma.hasMoreTokens()) {
String alias = stk_comma.nextToken();
cert = getCert(alias, ks);
}
return cert;
}
AuthBlock(Object[] message, String spi, int bsd, int lifetime)
throws ServiceLocationException, IllegalArgumentException {
ensureNonEmpty(message, "message");
Assert.nonNullParameter(spi, "spi");
this.bsd = bsd;
getSecurityProvider(bsd);
this.message = message;
this.spi = spi;
this.lifetime = lifetime;
this.timeStamp = SLPConfig.currentSLPTime() + lifetime;
try {
sig.initSign(null);
computeHash();
abBytes = sig.sign();
} catch (InvalidKeyException e) {
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() }));
}
abLength =
2 +
2 +
4 +
spiBytes.length +
abBytes.length;
}
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();
bsd = hdr.getInt(dis);
abLength = hdr.getInt(dis);
int pos = 4;
timeStamp = getInt32(dis);
pos += 4;
hdr.nbytes += 4;
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());
abBytes = new byte[abLength - pos];
dis.readFully(abBytes, 0, abLength - pos);
hdr.nbytes += abBytes.length;
long time = timeStamp - SLPConfig.currentSLPTime();
time = time <= Integer.MAX_VALUE ? time : 0;
lifetime = (int) time;
lifetime = lifetime < 0 ? 0 : lifetime;
getSecurityProvider(bsd);
}
int nBytes() {
return abLength;
}
Object[] getMessageParts() {
return message;
}
void verify() throws ServiceLocationException {
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()});
}
String u_DN = null;
try {
u_DN =
ServiceLocationAttribute.unescapeAttributeString(spi, false);
} catch (ServiceLocationException e) {
u_DN = spi;
}
X509Certificate cert = getCert(spi, ks);
try {
cert.checkValidity();
} catch (CertificateException e) {
throw new ServiceLocationException(
ServiceLocationException.AUTHENTICATION_FAILED,
"invalid_cert",
new Object[] {u_DN, e.getMessage()});
}
if (lifetime == 0) {
throw new ServiceLocationException(
ServiceLocationException.AUTHENTICATION_FAILED,
"timestamp_failure",
new Object[] {u_DN});
}
try {
checkSPIs(cert, ks);
} catch (GeneralSecurityException e) {
throw new ServiceLocationException(
ServiceLocationException.AUTHENTICATION_FAILED,
"cant_match_spis",
new Object[] {cert.getSubjectDN(), e.getMessage()});
}
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;
}
}
void externalize(SrvLocHeader hdr, ByteArrayOutputStream baos)
throws ServiceLocationException, IllegalArgumentException {
Assert.nonNullParameter(hdr, "hdr");
Assert.nonNullParameter(baos, "baos");
hdr.putInt(bsd, baos);
hdr.putInt(abLength, baos);
putInt32(timeStamp, baos);
hdr.nbytes += 4;
hdr.putString(spi, baos);
baos.write(abBytes, 0, abBytes.length);
hdr.nbytes += abBytes.length;
}
String getSPI() {
return spi;
}
int getLifetime() {
return lifetime;
}
private void getSecurityProvider(int bsd)
throws ServiceLocationException {
String algo = "Unknown BSD";
try {
if (bsd == 2) {
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) {
throw new ServiceLocationException(
ServiceLocationException.INTERNAL_SYSTEM_ERROR,
"cant_get_security_provider",
new Object[] {
Integer.valueOf(bsd),
algo,
e.getMessage()});
}
throw new ServiceLocationException(
ServiceLocationException.INTERNAL_SYSTEM_ERROR,
"cant_get_security_provider",
new Object[] {
Integer.valueOf(bsd),
algo,
"Unknown or unsupported BSD"});
}
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 {
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);
}
}
private void computeHash() throws ServiceLocationException {
try {
ByteArrayOutputStream baosT = new ByteArrayOutputStream();
SrvLocHeader.putStringField(spi, baosT, Defaults.UTF8);
spiBytes = baosT.toByteArray();
sig.update(spiBytes);
int mSize = message.length;
for (int i = 0; i < mSize; i++) {
sig.update((byte[]) message[i]);
}
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));
}
private void checkSPIs(X509Certificate cert, KeyStore ks)
throws ServiceLocationException, GeneralSecurityException {
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]);
}
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()});
}
int i = 0;
try {
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");
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;
}
throw new ServiceLocationException(
ServiceLocationException.AUTHENTICATION_FAILED,
"cant_match_spis",
new Object[] {cert.getSubjectDN().toString(), ""});
}
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;
}
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;
}
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 {
KeyStore ks = getKeyStore();
chain = ks.getCertificateChain(sub);
} catch (KeyStoreException e) {
throw ex;
}
if (chain == null) {
throw ex;
}
return onCertChain(ca, chain);
}
private static boolean onCertChain(Principal ca,
java.security.cert.Certificate[] chain)
{
for (int i = 0; i < chain.length; i++) {
Principal sub = ((X509Certificate)chain[i]).getSubjectDN();
if (ca.equals(sub)) {
return true;
}
}
return false;
}
private boolean inEqSet(Principal someDN) {
return eqSet.contains(someDN);
}
static private X509Certificate getCert(String DN, KeyStore ks)
throws ServiceLocationException {
X509Certificate cert = null;
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;
}
static private synchronized KeyStore getKeyPkg()
throws ServiceLocationException {
if (keypkg != null) {
return keypkg;
}
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;
}
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";
}
int bsd;
String spi;
Object[] message;
int lifetime;
long timeStamp;
SrvLocHeader hdr;
Signature sig;
int abLength;
byte[] abBytes;
byte[] spiBytes;
HashSet eqSet;
static private KeyStore keystore;
static private KeyStore keypkg;
}