CertificateMessage.java revision 2feeee4119506ed1511942f80fc2f7eb431afab7
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 java.io.IOException;
21import java.security.cert.Certificate;
22import java.security.cert.CertificateEncodingException;
23import java.security.cert.CertificateException;
24import java.security.cert.CertificateFactory;
25import java.security.cert.X509Certificate;
26import java.util.ArrayList;
27
28/**
29 * Represents server/client certificate message
30 * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS
31 * 1.0 spec., 7.4.2. Server certificate; 7.4.6. Client certificate</a>
32 *
33 */
34public class CertificateMessage extends Message {
35
36    /**
37     * Certificates
38     */
39    X509Certificate[] certs;
40
41    /**
42     * Certificates in encoded form
43     */
44    byte[][] encoded_certs;
45
46    /**
47     * Creates inbound message
48     *
49     * @param in
50     * @param length
51     * @throws IOException
52     */
53    public CertificateMessage(HandshakeIODataStream in, int length) throws IOException {
54        int l = in.readUint24(); // total_length
55        if (l == 0) {  // message contais no certificates
56            if (length != 3) { // no more bytes after total_length
57                fatalAlert(AlertProtocol.DECODE_ERROR,
58                        "DECODE ERROR: incorrect CertificateMessage");
59            }
60            certs = new X509Certificate[0];
61            encoded_certs = new byte[0][0];
62            this.length = 3;
63            return;
64        }
65        CertificateFactory cf;
66        try {
67            cf = CertificateFactory.getInstance("X509");
68        } catch (CertificateException e) {
69            fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e);
70            return;
71        }
72        ArrayList<X509Certificate> certsList = new ArrayList<X509Certificate>();
73        int size = 0;
74        int enc_size = 0;
75        while (l > 0) {
76            size = in.readUint24();
77            l -= 3;
78            try {
79                certsList.add((X509Certificate) cf.generateCertificate(in));
80            } catch (CertificateException e) {
81                fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR", e);
82            }
83            l -= size;
84            enc_size += size;
85        }
86        certs = certsList.toArray(new X509Certificate[certsList.size()]);
87        this.length = 3 + 3 * certs.length + enc_size;
88        if (this.length != length) {
89            fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect CertificateMessage");
90        }
91    }
92
93    /**
94     * Creates outbound message
95     *
96     * @param certs
97     */
98    public CertificateMessage(X509Certificate[] certs) {
99        if (certs == null) {
100            this.certs = new X509Certificate[0];
101            encoded_certs = new byte[0][0];
102            length = 3;
103            return;
104        }
105        this.certs = certs;
106        if (encoded_certs == null) {
107            encoded_certs = new byte[certs.length][];
108            for (int i = 0; i < certs.length; i++) {
109                try {
110                    encoded_certs[i] = certs[i].getEncoded();
111                } catch (CertificateEncodingException e) {
112                    fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR",
113                            e);
114                }
115            }
116        }
117        length = 3 + 3 * encoded_certs.length;
118        for (int i = 0; i < encoded_certs.length; i++) {
119            length += encoded_certs[i].length;
120        }
121    }
122
123    /**
124     * Sends message
125     *
126     * @param out
127     */
128    @Override
129    public void send(HandshakeIODataStream out) {
130
131        int total_length = 0;
132        if (encoded_certs == null) {
133            encoded_certs = new byte[certs.length][];
134            for (int i = 0; i < certs.length; i++) {
135                try {
136                    encoded_certs[i] = certs[i].getEncoded();
137                } catch (CertificateEncodingException e) {
138                    fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR",
139                            e);
140                }
141            }
142        }
143        total_length = 3 * encoded_certs.length;
144        for (int i = 0; i < encoded_certs.length; i++) {
145            total_length += encoded_certs[i].length;
146        }
147        out.writeUint24(total_length);
148        for (int i = 0; i < encoded_certs.length; i++) {
149            out.writeUint24(encoded_certs[i].length);
150            out.write(encoded_certs[i]);
151        }
152
153    }
154
155    public String getAuthType() {
156        return certs[0].getPublicKey().getAlgorithm();
157    }
158
159    /**
160     * Returns message type
161     *
162     * @return
163     */
164    @Override
165    public int getType() {
166        return Handshake.CERTIFICATE;
167    }
168
169}
170