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