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