1 /* 2 * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. 3 * 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 package sun.security.ssl; 26 27 import java.io.IOException; 28 import java.security.cert.CertificateEncodingException; 29 import java.security.cert.X509Certificate; 30 import java.util.Arrays; 31 import java.util.Objects; 32 33 import javax.net.ssl.CertificateAuthority; 34 35 import sun.security.util.DerOutputStream; 36 import sun.security.util.DerValue; 37 38 /** 39 * Implementation for {@link CertificateAuthority} interface. 40 * <p> 41 * A {@code CertificateAuthorityImpl} instance can be constructed 42 * by either: 43 * <ul> 44 * <li>providing a raw byte buffer to be parsed, or</li> 45 * <li>providing a X.509 certificate.</li> 46 * </ul> 47 * <p> 48 * When constructing an {@code CertificateAuthority} instance from 49 * a raw byte buffer, the certificate authority distinguished name 50 * is normalized to UTF-8 encoding for later comparisons. 51 * <p> 52 * {@code CertificateAuthorityImpl#implies(X509Certificate)} method 53 * builds a new {@code CertificateAuthorityImpl} instance, based on the 54 * X.509 certificate to be matched, and compares encoded byte arrays 55 * to decide if the certificate was indicated. 56 * <p> 57 * See further information in 58 * <a href="https://tools.ietf.org/html/draft-ietf-tls-tls13-20#section-4.2.4">TLS 1.3</a>. 59 * 60 * @see CertificateAuthoritiesExtension 61 * @see CertificateAuthority 62 * 63 * @author Martin Balao (mbalao@redhat.com) 64 */ 65 final class CertificateAuthorityImpl implements CertificateAuthority { 66 67 private static final String exceptionMessage = "Certificate Authority internal exception."; 68 69 private byte[] encodedData; 70 71 CertificateAuthorityImpl(byte[] encodedData, int offset, int length) throws IOException { 72 73 // Normalize the distinguished name in UTF-8 encoding 74 // so we can later compare CertificateAuthority objects. 75 final byte[] certificateDNDerEncoded = new byte[length]; 76 System.arraycopy(encodedData, offset, certificateDNDerEncoded, 0, 77 certificateDNDerEncoded.length); 78 final DerValue certificateDNDerValue = new DerValue(certificateDNDerEncoded); 79 80 byte[] certificateDNDerEncodedUTF8 = null; 81 try (DerOutputStream out = new DerOutputStream()) { 82 out.putUTF8String(certificateDNDerValue.getAsString()); 83 certificateDNDerEncodedUTF8 = out.toByteArray(); 84 } 85 86 this.encodedData = new byte[2 + certificateDNDerEncodedUTF8.length]; 87 this.encodedData[0] = (byte) ((certificateDNDerEncodedUTF8.length & 0xFF00) >> 8); 88 this.encodedData[1] = (byte) (certificateDNDerEncodedUTF8.length & 0xFF); 89 System.arraycopy(certificateDNDerEncodedUTF8, 0, this.encodedData, 2, 90 certificateDNDerEncodedUTF8.length); 91 } 92 93 CertificateAuthorityImpl(X509Certificate trustedCertificate) 94 throws CertificateEncodingException, Exception { 95 try (DerOutputStream out = new DerOutputStream()) { 96 out.putUTF8String(trustedCertificate.getSubjectDN().getName()); 97 final byte[] derEncodedName = out.toByteArray(); 98 if (derEncodedName.length <= 0 || derEncodedName.length > 0xFFFF) { 99 throw new IllegalArgumentException( 100 "Subject distinguished name on the trusted certificate has an invalid length."); 101 } 102 encodedData = new byte[2 + derEncodedName.length]; // 2 bytes for 103 // data length 104 encodedData[0] = (byte) ((derEncodedName.length & 0xFF00) >> 8); 105 encodedData[1] = (byte) (derEncodedName.length & 0xFF); 106 System.arraycopy(derEncodedName, 0, encodedData, 2, derEncodedName.length); 107 } catch (IOException e) { 108 throw new Exception(exceptionMessage, e); 109 } 110 } 111 112 @Override 113 public byte[] getEncoded() { 114 return encodedData; 115 } 116 117 @Override 118 public boolean implies(X509Certificate certificate) 119 throws CertificateEncodingException, Exception { 120 final CertificateAuthorityImpl certificateAuthority = 121 new CertificateAuthorityImpl(certificate); 122 return certificateAuthority.equals(this); 123 } 124 125 @Override 126 public boolean equals(Object o) { 127 if (o.getClass().equals(this.getClass())) { 128 return Arrays.equals(((CertificateAuthority) o).getEncoded(), this.getEncoded()); 129 } 130 return false; 131 } 132 133 @Override 134 public int hashCode() { 135 return Objects.hashCode(encodedData); 136 } 137 138 }