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.X509Certificate; 22 import java.util.ArrayList; 23 import javax.security.auth.x500.X500Principal; 24 import libcore.io.Streams; 25 26 /** 27 * 28 * Represents certificate request message 29 * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.4. 30 * Certificate request</a> 31 */ 32 public class CertificateRequest extends Message { 33 34 /** 35 * Requested certificate types 36 */ 37 final byte[] certificate_types; 38 39 /** 40 * Certificate authorities 41 */ 42 final X500Principal[] certificate_authorities; 43 44 /** 45 * Requested certificate types as Strings 46 * ("RSA", "DSA", "DH_RSA" or "DH_DSA") 47 */ 48 private String[] types; 49 50 /** 51 * Encoded form of certificate authorities 52 */ 53 private byte[][] encoded_principals; 54 55 /** 56 * Creates outbound message 57 * 58 * @param certificate_types 59 * @param accepted - array of certificate authority certificates 60 */ 61 public CertificateRequest(byte[] certificate_types, 62 X509Certificate[] accepted) { 63 64 if (accepted == null) { 65 fatalAlert(AlertProtocol.INTERNAL_ERROR, 66 "CertificateRequest: array of certificate authority certificates is null"); 67 } 68 this.certificate_types = certificate_types; 69 70 int totalPrincipalsLength = 0; 71 certificate_authorities = new X500Principal[accepted.length]; 72 encoded_principals = new byte[accepted.length][]; 73 for (int i = 0; i < accepted.length; i++) { 74 certificate_authorities[i] = accepted[i].getIssuerX500Principal(); 75 encoded_principals[i] = certificate_authorities[i].getEncoded(); 76 totalPrincipalsLength += encoded_principals[i].length + 2; 77 } 78 79 length = 3 + certificate_types.length + totalPrincipalsLength; 80 } 81 82 /** 83 * Creates inbound message 84 * 85 * @param in 86 * @param length 87 * @throws IOException 88 */ 89 public CertificateRequest(HandshakeIODataStream in, int length) throws IOException { 90 int size = in.readUint8(); 91 certificate_types = new byte[size]; 92 Streams.readFully(in, certificate_types); 93 size = in.readUint16(); 94 int totalPrincipalsLength = 0; 95 int principalLength = 0; 96 ArrayList<X500Principal> principals = new ArrayList<X500Principal>(); 97 while (totalPrincipalsLength < size) { 98 principalLength = in.readUint16(); // encoded X500Principal size 99 principals.add(new X500Principal(in)); 100 totalPrincipalsLength += 2; 101 totalPrincipalsLength += principalLength; 102 } 103 certificate_authorities = principals.toArray(new X500Principal[principals.size()]); 104 this.length = 3 + certificate_types.length + totalPrincipalsLength; 105 if (this.length != length) { 106 fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect CertificateRequest"); 107 } 108 } 109 110 /** 111 * Sends message 112 * 113 * @param out 114 */ 115 @Override 116 public void send(HandshakeIODataStream out) { 117 118 out.writeUint8(certificate_types.length); 119 for (int i = 0; i < certificate_types.length; i++) { 120 out.write(certificate_types[i]); 121 } 122 int authoritiesLength = 0; 123 for (int i = 0; i < certificate_authorities.length; i++) { 124 authoritiesLength += encoded_principals[i].length +2; 125 } 126 out.writeUint16(authoritiesLength); 127 for (int i = 0; i < certificate_authorities.length; i++) { 128 out.writeUint16(encoded_principals[i].length); 129 out.write(encoded_principals[i]); 130 } 131 } 132 133 /** 134 * Returns message type 135 */ 136 @Override 137 public int getType() { 138 return Handshake.CERTIFICATE_REQUEST; 139 } 140 141 /** 142 * Returns requested certificate types as array of strings 143 */ 144 public String[] getTypesAsString() { 145 if (types == null) { 146 types = new String[certificate_types.length]; 147 for (int i = 0; i < types.length; i++) { 148 String type = CipherSuite.getClientKeyType(certificate_types[i]); 149 if (type == null) { 150 fatalAlert(AlertProtocol.DECODE_ERROR, 151 "DECODE ERROR: incorrect CertificateRequest"); 152 } 153 types[i] = type; 154 } 155 } 156 return types; 157 } 158 159 } 160