/* * 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 org.apache.harmony.xnet.provider.jsse; import org.apache.harmony.xnet.provider.jsse.Message; import org.apache.harmony.xnet.provider.jsse.Handshake; import org.apache.harmony.xnet.provider.jsse.HandshakeIODataStream; import org.apache.harmony.xnet.provider.jsse.AlertProtocol; import java.io.IOException; import java.security.cert.X509Certificate; import java.util.Vector; import javax.security.auth.x500.X500Principal; /** * * Represents certificate request message * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.4. * Certificate request</a> */ public class CertificateRequest extends Message { /** * Client certificate types as defined in * TLS 1.0 spec., 7.4.4. Certificate request */ public static final byte RSA_SIGN = 1; public static final byte DSS_SIGN = 2; public static final byte RSA_FIXED_DH = 3; public static final byte DSS_FIXED_DH = 4; /** * Requested certificate types */ final byte[] certificate_types; /** * Certificate authorities */ X500Principal[] certificate_authorities; //Requested certificate types as Strings // ("RSA", "DSA", "DH_RSA" or "DH_DSA") private String[] types; // Encoded form of certificate authorities private byte[][] encoded_principals; /** * Creates outbound message * * @param certificate_types * @param accepted - array of certificate authority certificates */ public CertificateRequest(byte[] certificate_types, X509Certificate[] accepted) { if (accepted == null) { fatalAlert(AlertProtocol.INTERNAL_ERROR, "CertificateRequest: array of certificate authority certificates is null"); } this.certificate_types = certificate_types; int totalPrincipalsLength = 0; certificate_authorities = new X500Principal[accepted.length]; encoded_principals = new byte[accepted.length][]; for (int i = 0; i < accepted.length; i++) { certificate_authorities[i] = accepted[i].getIssuerX500Principal(); encoded_principals[i] = certificate_authorities[i].getEncoded(); totalPrincipalsLength += encoded_principals[i].length + 2; } length = 3 + certificate_types.length + totalPrincipalsLength; } /** * Creates inbound message * * @param in * @param length * @throws IOException */ public CertificateRequest(HandshakeIODataStream in, int length) throws IOException { int size = in.readUint8(); certificate_types = new byte[size]; in.read(certificate_types, 0, size); size = in.readUint16(); certificate_authorities = new X500Principal[size]; int totalPrincipalsLength = 0; int principalLength = 0; Vector<X500Principal> principals = new Vector<X500Principal>(); while (totalPrincipalsLength < size) { principalLength = in.readUint16(); // encoded X500Principal size principals.add(new X500Principal(in)); totalPrincipalsLength += 2; totalPrincipalsLength += principalLength; } certificate_authorities = new X500Principal[principals.size()]; for (int i = 0; i < certificate_authorities.length; i++) { certificate_authorities[i] = principals.elementAt(i); } this.length = 3 + certificate_types.length + totalPrincipalsLength; if (this.length != length) { fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect CertificateRequest"); } } /** * Sends message * * @param out */ @Override public void send(HandshakeIODataStream out) { out.writeUint8(certificate_types.length); for (int i = 0; i < certificate_types.length; i++) { out.write(certificate_types[i]); } int authoritiesLength = 0; for (int i = 0; i < certificate_authorities.length; i++) { authoritiesLength += encoded_principals[i].length +2; } out.writeUint16(authoritiesLength); for (int i = 0; i < certificate_authorities.length; i++) { out.writeUint16(encoded_principals[i].length); out.write(encoded_principals[i]); } } /** * Returns message type * * @return */ @Override public int getType() { return Handshake.CERTIFICATE_REQUEST; } /** * Returns requested certificate types as array of strings */ public String[] getTypesAsString() { if (types == null) { types = new String[certificate_types.length]; for (int i = 0; i < types.length; i++) { switch (certificate_types[i]) { case 1: types[i] = "RSA"; break; case 2: types[i] = "DSA"; break; case 3: types[i] = "DH_RSA"; break; case 4: types[i] = "DH_DSA"; break; default: fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect CertificateRequest"); } } } return types; } }