1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.xnet.provider.jsse;
19
20import org.apache.harmony.xnet.provider.jsse.Message;
21import org.apache.harmony.xnet.provider.jsse.Handshake;
22import org.apache.harmony.xnet.provider.jsse.HandshakeIODataStream;
23import org.apache.harmony.xnet.provider.jsse.AlertProtocol;
24
25import java.io.IOException;
26import java.security.cert.X509Certificate;
27import java.util.Vector;
28
29import javax.security.auth.x500.X500Principal;
30
31/**
32 *
33 * Represents certificate request message
34 * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.4.
35 * Certificate request</a>
36 */
37public class CertificateRequest extends Message {
38
39    /**
40     * Client certificate types as defined in
41     * TLS 1.0 spec., 7.4.4. Certificate request
42     */
43    public static final byte RSA_SIGN = 1;
44    public static final byte DSS_SIGN = 2;
45    public static final byte RSA_FIXED_DH = 3;
46    public static final byte DSS_FIXED_DH = 4;
47
48    /**
49     * Requested certificate types
50     */
51    final byte[] certificate_types;
52
53    /**
54     * Certificate authorities
55     */
56    X500Principal[] certificate_authorities;
57
58    //Requested certificate types as Strings
59    // ("RSA", "DSA", "DH_RSA" or "DH_DSA")
60    private String[] types;
61
62    // Encoded form of certificate authorities
63    private byte[][] encoded_principals;
64
65    /**
66     * Creates outbound message
67     *
68     * @param certificate_types
69     * @param accepted - array of certificate authority certificates
70     */
71    public CertificateRequest(byte[] certificate_types,
72            X509Certificate[] accepted) {
73
74        if (accepted == null) {
75            fatalAlert(AlertProtocol.INTERNAL_ERROR,
76                    "CertificateRequest: array of certificate authority certificates is null");
77        }
78        this.certificate_types = certificate_types;
79
80        int totalPrincipalsLength = 0;
81        certificate_authorities = new X500Principal[accepted.length];
82        encoded_principals = new byte[accepted.length][];
83        for (int i = 0; i < accepted.length; i++) {
84            certificate_authorities[i] = accepted[i].getIssuerX500Principal();
85            encoded_principals[i] = certificate_authorities[i].getEncoded();
86            totalPrincipalsLength += encoded_principals[i].length + 2;
87        }
88
89        length = 3 + certificate_types.length + totalPrincipalsLength;
90    }
91
92    /**
93     * Creates inbound message
94     *
95     * @param in
96     * @param length
97     * @throws IOException
98     */
99    public CertificateRequest(HandshakeIODataStream in, int length)
100            throws IOException {
101        int size = in.readUint8();
102        certificate_types = new byte[size];
103        in.read(certificate_types, 0, size);
104        size = in.readUint16();
105        certificate_authorities = new X500Principal[size];
106        int totalPrincipalsLength = 0;
107        int principalLength = 0;
108        Vector<X500Principal> principals = new Vector<X500Principal>();
109        while (totalPrincipalsLength < size) {
110            principalLength = in.readUint16(); // encoded X500Principal size
111            principals.add(new X500Principal(in));
112            totalPrincipalsLength += 2;
113            totalPrincipalsLength += principalLength;
114        }
115        certificate_authorities = new X500Principal[principals.size()];
116        for (int i = 0; i < certificate_authorities.length; i++) {
117            certificate_authorities[i] = principals.elementAt(i);
118        }
119        this.length = 3 + certificate_types.length + totalPrincipalsLength;
120        if (this.length != length) {
121            fatalAlert(AlertProtocol.DECODE_ERROR,
122                    "DECODE ERROR: incorrect CertificateRequest");
123        }
124
125    }
126
127    /**
128     * Sends message
129     *
130     * @param out
131     */
132    @Override
133    public void send(HandshakeIODataStream out) {
134
135        out.writeUint8(certificate_types.length);
136        for (int i = 0; i < certificate_types.length; i++) {
137            out.write(certificate_types[i]);
138        }
139        int authoritiesLength = 0;
140        for (int i = 0; i < certificate_authorities.length; i++) {
141            authoritiesLength += encoded_principals[i].length +2;
142        }
143        out.writeUint16(authoritiesLength);
144        for (int i = 0; i < certificate_authorities.length; i++) {
145            out.writeUint16(encoded_principals[i].length);
146            out.write(encoded_principals[i]);
147        }
148    }
149
150    /**
151     * Returns message type
152     *
153     * @return
154     */
155    @Override
156    public int getType() {
157        return Handshake.CERTIFICATE_REQUEST;
158    }
159
160    /**
161     * Returns requested certificate types as array of strings
162     */
163    public String[] getTypesAsString() {
164        if (types == null) {
165            types = new String[certificate_types.length];
166            for (int i = 0; i < types.length; i++) {
167                switch (certificate_types[i]) {
168                case 1:
169                    types[i] = "RSA";
170                    break;
171                case 2:
172                    types[i] = "DSA";
173                    break;
174                case 3:
175                    types[i] = "DH_RSA";
176                    break;
177                case 4:
178                    types[i] = "DH_DSA";
179                    break;
180                default:
181                    fatalAlert(AlertProtocol.DECODE_ERROR,
182                            "DECODE ERROR: incorrect CertificateRequest");
183                }
184            }
185        }
186        return types;
187    }
188
189}
190