Home | History | Annotate | Download | only in jsse
      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 
     18 package org.apache.harmony.xnet.provider.jsse;
     19 
     20 import java.io.IOException;
     21 import java.security.cert.Certificate;
     22 import java.security.cert.CertificateEncodingException;
     23 import java.security.cert.CertificateException;
     24 import java.security.cert.CertificateFactory;
     25 import java.security.cert.X509Certificate;
     26 import 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  */
     34 public 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