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