/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.sun.jini.discovery.internal; import com.sun.jini.discovery.DatagramBufferFactory; import com.sun.jini.discovery.DelayedMulticastAnnouncementDecoder; import com.sun.jini.discovery.DiscoveryProtocolException; import com.sun.jini.discovery.MulticastAnnouncement; import com.sun.jini.discovery.MulticastRequest; import com.sun.jini.discovery.MulticastRequestEncoder; import java.io.IOException; import java.nio.ByteBuffer; import java.util.logging.Level; import java.security.cert.Certificate; import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500PrivateCredential; import net.jini.core.constraint.InvocationConstraints; import net.jini.io.UnsupportedConstraintException; /** * Superclass for client-side providers for the net.jini.discovery.x500.* * discovery formats. */ public class X500Client extends X500Provider implements MulticastRequestEncoder, DelayedMulticastAnnouncementDecoder { /** * Creates an instance with the given attributes. */ protected X500Client(String formatName, String signatureAlgorithm, int maxSignatureLength, String keyAlgorithm, String keyAlgorithmOID) { super(formatName, signatureAlgorithm, maxSignatureLength, keyAlgorithm, keyAlgorithmOID); } // documentation inherited from MulticastRequestEncoder public void encodeMulticastRequest(MulticastRequest request, DatagramBufferFactory bufs, InvocationConstraints constraints) throws IOException { if (request == null || bufs == null) { throw new NullPointerException(); } try { X500Constraints cons = X500Constraints.process(constraints, true); // REMIND: instead iterate through constraint-designated principals X500PrivateCredential[] creds = getPrivateCredentials(); X500PrivateCredential chosen = null; int best = -1; SecurityException se = null; for (int i = 0; i < creds.length; i++) { X500PrivateCredential c = creds[i]; X500Principal p = c.getCertificate().getSubjectX500Principal(); int score = cons.checkClientPrincipal(p); if (score < 0) { if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "skipping disallowed principal {0}", new Object[]{ p }); } continue; } try { checkAuthenticationPermission(p, "connect"); } catch (SecurityException e) { se = e; if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "not authorized to use principal {0}", new Object[]{ p }); } continue; } if (score > best) { chosen = c; best = score; } } if (chosen == null) { UnsupportedConstraintException uce = new UnsupportedConstraintException( "unsupported constraints: " + constraints); if (se != null) { // At least one principal was rejected due to lack // of authentication permissions secureThrow(se, uce); } throw uce; } if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "using principal {0}", new Object[]{ chosen }); } SigningBufferFactory sbf = new SigningBufferFactory(bufs, chosen); Plaintext.encodeMulticastRequest(request, sbf); sbf.sign(); } catch (IOException e) { throw e; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new DiscoveryProtocolException(null, e); } } // documentation inherited from MulticastAnnouncementDecoder public MulticastAnnouncement decodeMulticastAnnouncement( ByteBuffer buf, InvocationConstraints constraints, boolean delayConstraintCheck) throws IOException { try { int len = buf.getInt(); ByteBuffer data = buf.duplicate(); data.limit(data.position() + len); buf.position(data.limit()); X500Principal p = new X500Principal(Plaintext.getUtf(buf)); ByteBuffer signed = (ByteBuffer) data.duplicate().position(0); MulticastAnnouncement ma = Plaintext.decodeMulticastAnnouncement(data); ma = new X500MulticastAnnouncement(ma, constraints, p, buf.duplicate(), signed); if (!delayConstraintCheck) { ma.checkConstraints(); } return ma; } catch (IOException e) { throw e; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new DiscoveryProtocolException(null, e); } } public MulticastAnnouncement decodeMulticastAnnouncement(ByteBuffer buf, InvocationConstraints constraints) throws IOException { return decodeMulticastAnnouncement(buf, constraints, false); } private class X500MulticastAnnouncement extends MulticastAnnouncement { private final InvocationConstraints constraints; private final X500Principal p; private final ByteBuffer signature; private final ByteBuffer signed; private X500MulticastAnnouncement(MulticastAnnouncement plainMA, InvocationConstraints constraints, X500Principal p, ByteBuffer signature, ByteBuffer signed) { super(plainMA.getSequenceNumber(), plainMA.getHost(), plainMA.getPort(), plainMA.getGroups(), plainMA.getServiceID()); this.constraints = constraints; this.p = p; this.signature = signature; this.signed = signed; } public void checkConstraints() throws IOException { try { X500Constraints cons = X500Constraints.process(constraints, false); if (cons.checkServerPrincipal(p) < 0) { throw new UnsupportedConstraintException( "principal not allowed: " + p); } Certificate cert = getCertificate(p); if (cert == null) { throw new DiscoveryProtocolException( "unknown principal: " + p); } if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "mapped principal {0} to {1}", new Object[]{ p, cert }); } if (!verify(signed.duplicate(), signature.duplicate(), cert.getPublicKey())) { throw new DiscoveryProtocolException( "signature verification failed: " + p); } } catch (IOException e) { throw e; } catch (SecurityException e) { throw e; } catch (Exception e) { throw new DiscoveryProtocolException(null, e); } } } }