1 /* 2 * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.jndi.ldap.sasl; 26 27 import javax.naming.NamingException; 28 import javax.security.sasl.SaslException; 29 import java.security.MessageDigest; 30 import java.security.NoSuchAlgorithmException; 31 import java.security.cert.CertificateEncodingException; 32 import java.security.cert.X509Certificate; 33 import java.util.Arrays; 34 import java.util.Hashtable; 35 36 /** 37 * This class implements the Channel Binding for TLS as defined in 38 * <a href="https://www.ietf.org/rfc/rfc5929.txt"> 39 * Channel Bindings for TLS</a> 40 * 41 * Format of the Channel Binding data is also defined in 42 * <a href="https://www.ietf.org/rfc/rfc5056.txt"> 43 * On the Use of Channel Bindings to Secure Channels</a> 44 * section 2.1. 45 * 46 */ 47 48 public class TlsChannelBinding { 49 50 // TLS channel binding type property 51 public static final String CHANNEL_BINDING_TYPE = 52 "com.sun.jndi.ldap.tls.cbtype"; 53 54 // internal TLS channel binding property 55 public static final String CHANNEL_BINDING = 56 "jdk.internal.sasl.tlschannelbinding"; 57 58 public enum TlsChannelBindingType { 59 60 /** 61 * Channel binding on the basis of TLS Finished message. 62 * TLS_UNIQUE is defined by RFC 5929 but is not supported 63 * by the current LDAP stack. 64 */ 65 TLS_UNIQUE("tls-unique"), 66 67 /** 68 * Channel binding on the basis of TLS server certificate. 69 */ 70 TLS_SERVER_END_POINT("tls-server-end-point"); 71 getName()72 public String getName() { 73 return name; 74 } 75 76 final private String name; TlsChannelBindingType(String name)77 TlsChannelBindingType(String name) { 78 this.name = name; 79 } 80 } 81 82 /** 83 * Parse value of "com.sun.jndi.ldap.tls.cbtype" property 84 * @param cbType 85 * @return TLS Channel Binding type or null if 86 * "com.sun.jndi.ldap.tls.cbtype" property has not been set. 87 * @throws NamingException 88 */ parseType(String cbType)89 public static TlsChannelBindingType parseType(String cbType) throws NamingException { 90 if (cbType != null) { 91 if (cbType.equals(TlsChannelBindingType.TLS_SERVER_END_POINT.getName())) { 92 return TlsChannelBindingType.TLS_SERVER_END_POINT; 93 } else { 94 throw new NamingException("Illegal value for " + 95 CHANNEL_BINDING_TYPE + " property."); 96 } 97 } 98 return null; 99 } 100 101 final private TlsChannelBindingType cbType; 102 final private byte[] cbData; 103 104 /** 105 * Construct tls-server-end-point Channel Binding data 106 * @param serverCertificate 107 * @throws SaslException 108 */ create(X509Certificate serverCertificate)109 public static TlsChannelBinding create(X509Certificate serverCertificate) throws SaslException { 110 try { 111 final byte[] prefix = 112 TlsChannelBindingType.TLS_SERVER_END_POINT.getName().concat(":").getBytes(); 113 String hashAlg = serverCertificate.getSigAlgName(). 114 replace("SHA", "SHA-").toUpperCase(); 115 int ind = hashAlg.indexOf("WITH"); 116 if (ind > 0) { 117 hashAlg = hashAlg.substring(0, ind); 118 if (hashAlg.equals("MD5") || hashAlg.equals("SHA-1")) { 119 hashAlg = "SHA-256"; 120 } 121 } else { 122 hashAlg = "SHA-256"; 123 } 124 MessageDigest md = MessageDigest.getInstance(hashAlg); 125 byte[] hash = md.digest(serverCertificate.getEncoded()); 126 byte[] cbData = Arrays.copyOf(prefix, prefix.length + hash.length ); 127 System.arraycopy(hash, 0, cbData, prefix.length, hash.length); 128 return new TlsChannelBinding(TlsChannelBindingType.TLS_SERVER_END_POINT, cbData); 129 } catch (NoSuchAlgorithmException | CertificateEncodingException e) { 130 throw new SaslException("Cannot create TLS channel binding data", e); 131 } 132 } 133 TlsChannelBinding(TlsChannelBindingType cbType, byte[] cbData)134 private TlsChannelBinding(TlsChannelBindingType cbType, byte[] cbData) { 135 this.cbType = cbType; 136 this.cbData = cbData; 137 } 138 getType()139 public TlsChannelBindingType getType() { 140 return cbType; 141 } 142 getData()143 public byte[] getData() { 144 return cbData; 145 } 146 } 147