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 18package java.security.cert; 19 20import java.io.IOException; 21import java.security.PublicKey; 22import javax.security.auth.x500.X500Principal; 23import org.apache.harmony.security.utils.Array; 24import org.apache.harmony.security.x509.NameConstraints; 25 26 27 28/** 29 * This class represents a trust anchor for validation of X.509 certification 30 * path. 31 * <p> 32 * It is a <i>trusted</i> certificate authority (CA) and includes the public key 33 * of the CA, the CA's name and the constraints for the validation of 34 * certification paths. The constructor also allows to specify a binary 35 * representation of a so called "Name Constraints" extension as a byte array. 36 */ 37public class TrustAnchor { 38 // Most trusted CA as a X500Principal 39 private final X500Principal caPrincipal; 40 // Most trusted CA name 41 private final String caName; 42 // Most trusted CA public key 43 private final PublicKey caPublicKey; 44 // Most trusted CA certificate 45 private final X509Certificate trustedCert; 46 // Name constraints extension 47 private final byte[] nameConstraints; 48 49 /** 50 * Creates a new {@code TrustAnchor} with the specified certificate and name 51 * constraints. 52 * <p> 53 * The name constraints will be used as additional constraints during the 54 * validation of certification paths. 55 * 56 * @param trustedCert 57 * the trusted certificate 58 * @param nameConstraints 59 * the ASN.1 DER encoded form of the name constraints or {@code 60 * null} if none. 61 * @throws IllegalArgumentException 62 * if the decoding of the name constraints fail. 63 */ 64 public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) { 65 if (trustedCert == null) { 66 throw new NullPointerException("trustedCert == null"); 67 } 68 this.trustedCert = trustedCert; 69 // copy nameConstraints if not null 70 if (nameConstraints != null) { 71 this.nameConstraints = new byte[nameConstraints.length]; 72 System.arraycopy(nameConstraints, 0, 73 this.nameConstraints, 0, this.nameConstraints.length); 74 processNameConstraints(); 75 } else { 76 this.nameConstraints = null; 77 } 78 this.caName = null; 79 this.caPrincipal = null; 80 this.caPublicKey = null; 81 } 82 83 /** 84 * Creates a new {@code TrustAnchor} with the specified certificate 85 * authority name, its public key and the specified name constraints. 86 * <p> 87 * The name constraints will be used as additional constraints during the 88 * validation of certification paths. 89 * 90 * @param caName 91 * the X.500 name of the certificate authority in RFC 2253 92 * {@code String} format. 93 * @param caPublicKey 94 * the public key of the certificate authority 95 * @param nameConstraints 96 * the ASN.1 DER encoded form of the name constraints or {@code 97 * null} if none. 98 * @throws IllegalArgumentException 99 * if the {@code caName} is empty or if decoding of the name 100 * constraints fail. 101 */ 102 public TrustAnchor(String caName, PublicKey caPublicKey, 103 byte[] nameConstraints) { 104 if (caName == null) { 105 throw new NullPointerException("caName == null"); 106 } 107 this.caName = caName; 108 if (caPublicKey == null) { 109 throw new NullPointerException("caPublicKey == null"); 110 } 111 this.caPublicKey = caPublicKey; 112 // copy nameConstraints if not null 113 if (nameConstraints != null) { 114 this.nameConstraints = new byte[nameConstraints.length]; 115 System.arraycopy(nameConstraints, 0, 116 this.nameConstraints, 0, this.nameConstraints.length); 117 processNameConstraints(); 118 } else { 119 this.nameConstraints = null; 120 } 121 122 this.trustedCert = null; 123 124 // X500Principal checks caName validity 125 if (caName.isEmpty()) { 126 throw new IllegalArgumentException("caName.isEmpty()"); 127 } 128 this.caPrincipal = new X500Principal(this.caName); 129 } 130 131 /** 132 * Creates a new {@code TrustAnchor} with the specified certificate 133 * authority name as principal, its public key and the specified name 134 * constraints. 135 * <p> 136 * The name constraints will be used as additional constraints during the 137 * validation of certification paths. 138 * 139 * @param caPrincipal 140 * the name of the certificate authority as X500 principal. 141 * @param caPublicKey 142 * the public key of the certificate authority. 143 * @param nameConstraints 144 * the ASN.1 DER encoded form of the name constraints or {@code 145 * null} if none. 146 * @throws IllegalArgumentException 147 * if decoding of the name constraints fail. 148 */ 149 public TrustAnchor(X500Principal caPrincipal, 150 PublicKey caPublicKey, byte[] nameConstraints) { 151 if (caPrincipal == null) { 152 throw new NullPointerException("caPrincipal == null"); 153 } 154 this.caPrincipal = caPrincipal; 155 if (caPublicKey == null) { 156 throw new NullPointerException("caPublicKey == null"); 157 } 158 this.caPublicKey = caPublicKey; 159 // copy nameConstraints if not null 160 if (nameConstraints != null) { 161 this.nameConstraints = new byte[nameConstraints.length]; 162 System.arraycopy(nameConstraints, 0, 163 this.nameConstraints, 0, this.nameConstraints.length); 164 processNameConstraints(); 165 } else { 166 this.nameConstraints = null; 167 } 168 169 this.trustedCert = null; 170 this.caName = caPrincipal.getName(); 171 } 172 173 /** 174 * Returns a copy of the name constraints in ASN.1 DER encoded form. 175 * 176 * @return a copy of the name constraints in ASN.1 DER encoded form. 177 */ 178 public final byte[] getNameConstraints() { 179 if (nameConstraints == null) { 180 return null; 181 } 182 byte[] ret = new byte[nameConstraints.length]; 183 System.arraycopy(nameConstraints, 0, 184 ret, 0, nameConstraints.length); 185 return ret; 186 } 187 188 /** 189 * Returns the certificate of this <i>trusted</i> certificate authority. 190 * 191 * @return the certificate of this CA or {@code null}, if the trust anchor 192 * of this instance was not created with a certificate. 193 */ 194 public final X509Certificate getTrustedCert() { 195 return trustedCert; 196 } 197 198 /** 199 * Returns the name of the certificate authority as {@code X500Principal}. 200 * 201 * @return the name of the certificate authority or {@code null} if the 202 * trust anchor of this instance was not created with a {@code 203 * X500Principal}. 204 */ 205 public final X500Principal getCA() { 206 return caPrincipal; 207 } 208 209 /** 210 * Returns the name of the certificate authority as {@code String} in RFC 211 * 2253 format. 212 * 213 * @return the name of the certificate authority as {@code String} in RFC 214 * 2253 format or {@code null} if the trust anchor of this instance 215 * was not created with a CA name. 216 */ 217 public final String getCAName() { 218 return caName; 219 } 220 221 /** 222 * Returns the public key of the certificate authority. 223 * 224 * @return the public key of the certificate authority or {@code null} if 225 * the trust anchor if this instance was not created with a public 226 * key. 227 */ 228 public final PublicKey getCAPublicKey() { 229 return caPublicKey; 230 } 231 232 /** 233 * Returns a string representation of this {@code TrustAnchor} instance. 234 * 235 * @return a string representation of this {@code TrustAnchor} instance. 236 */ 237 public String toString() { 238 StringBuilder sb = new StringBuilder("TrustAnchor: [\n"); 239 if (trustedCert != null) { 240 sb.append("Trusted CA certificate: "); 241 sb.append(trustedCert); 242 sb.append("\n"); 243 } 244 if (caPrincipal != null) { 245 sb.append("Trusted CA Name: "); 246 sb.append(caPrincipal); 247 sb.append("\n"); 248 } 249 if (caPublicKey != null) { 250 sb.append("Trusted CA Public Key: "); 251 sb.append(caPublicKey); 252 sb.append("\n"); 253 } 254 // FIXME if needed: 255 if (nameConstraints != null) { 256 sb.append("Name Constraints:\n"); 257 sb.append(Array.toString(nameConstraints, " ")); 258 } 259 sb.append("\n]"); 260 return sb.toString(); 261 } 262 263 // 264 // Private stuff 265 // 266 267 // Decodes and checks NameConstraints structure. 268 // Throws IllegalArgumentException if NameConstraints 269 // encoding is invalid. 270 private void processNameConstraints() { 271 try { 272 // decode and check nameConstraints 273 NameConstraints.ASN1.decode(nameConstraints); 274 } catch (IOException e) { 275 throw new IllegalArgumentException(e.getMessage()); 276 } 277 } 278} 279