001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2015 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018import org.forgerock.i18n.LocalizableMessage; 019 020 021 022import java.io.BufferedReader; 023import java.io.InputStreamReader; 024import java.io.IOException; 025import java.security.cert.CertificateException; 026import java.security.cert.X509Certificate; 027import java.util.Date; 028import javax.net.ssl.TrustManager; 029import javax.net.ssl.X509TrustManager; 030 031import static org.opends.messages.ToolMessages.*; 032 033 034 035/** 036 * This class provides an implementation of an X.509 trust manager which will 037 * interactively prompt the user (via the CLI) whether a given certificate 038 * should be trusted. It should only be used by interactive command-line tools, 039 * since it will block until it gets a response from the user. 040 * <BR><BR> 041 * Note that this class is only intended for client-side use, and therefore may 042 * not be used by a server to determine whether a client certificate is trusted. 043 */ 044public class PromptTrustManager 045 implements X509TrustManager 046{ 047 048 049 050 /** The singleton trust manager array for this class. */ 051 private static TrustManager[] trustManagerArray = 052 new TrustManager[] { new PromptTrustManager() }; 053 054 055 056 /** 057 * Creates a new instance of this prompt trust manager. 058 */ 059 private PromptTrustManager() 060 { 061 // No implementation is required. 062 } 063 064 065 066 /** 067 * Retrieves the trust manager array that should be used to initialize an SSL 068 * context in cases where the user should be interactively prompted about 069 * whether to trust the server certificate. 070 * 071 * @return The trust manager array that should be used to initialize an SSL 072 * context in cases where the user should be interactively prompted 073 * about whether to trust the server certificate. 074 */ 075 public static TrustManager[] getTrustManagers() 076 { 077 return trustManagerArray; 078 } 079 080 081 082 /** 083 * Determines whether an SSL client with the provided certificate chain should 084 * be trusted. This implementation is not intended for server-side use, and 085 * therefore this method will always throw an exception. 086 * 087 * @param chain The certificate chain for the SSL client. 088 * @param authType The authentication type based on the client certificate. 089 * 090 * @throws CertificateException To indicate that the provided client 091 * certificate is not trusted. 092 */ 093 public void checkClientTrusted(X509Certificate[] chain, String authType) 094 throws CertificateException 095 { 096 LocalizableMessage message = ERR_PROMPTTM_REJECTING_CLIENT_CERT.get(); 097 throw new CertificateException(message.toString()); 098 } 099 100 101 102 /** 103 * Determines whether an SSL server with the provided certificate chain should 104 * be trusted. In this case, the user will be interactively prompted as to 105 * whether the certificate should be trusted. 106 * 107 * @param chain The certificate chain for the SSL server. 108 * @param authType The key exchange algorithm used. 109 * 110 * @throws CertificateException If the user rejects the certificate. 111 */ 112 public void checkServerTrusted(X509Certificate[] chain, String authType) 113 throws CertificateException 114 { 115 if (chain == null || chain.length == 0) 116 { 117 System.out.println(WARN_PROMPTTM_NO_SERVER_CERT_CHAIN.get()); 118 } 119 else 120 { 121 Date currentDate = new Date(); 122 Date notAfterDate = chain[0].getNotAfter(); 123 Date notBeforeDate = chain[0].getNotBefore(); 124 125 if (currentDate.after(notAfterDate)) 126 { 127 System.err.println(WARN_PROMPTTM_CERT_EXPIRED.get(notAfterDate)); 128 } 129 else if (currentDate.before(notBeforeDate)) 130 { 131 System.err.println(WARN_PROMPTTM_CERT_NOT_YET_VALID.get(notBeforeDate)); 132 } 133 134 System.out.println(INFO_PROMPTTM_SERVER_CERT.get( 135 chain[0].getSubjectDN().getName(), 136 chain[0].getIssuerDN().getName(), 137 notBeforeDate, 138 notAfterDate)); 139 } 140 141 142 LocalizableMessage prompt = INFO_PROMPTTM_YESNO_PROMPT.get(); 143 BufferedReader reader = 144 new BufferedReader(new InputStreamReader(System.in)); 145 while (true) 146 { 147 try 148 { 149 System.out.print(prompt); 150 String line = reader.readLine().toLowerCase(); 151 if (line.equalsIgnoreCase( 152 INFO_PROMPT_YES_COMPLETE_ANSWER.get().toString()) || 153 line.equalsIgnoreCase( 154 INFO_PROMPT_YES_FIRST_LETTER_ANSWER.get().toString())) 155 { 156 // Returning without an exception is sufficient to consider the 157 // certificate trusted. 158 return; 159 } 160 if (line.equalsIgnoreCase( 161 INFO_PROMPT_NO_COMPLETE_ANSWER.get().toString()) || 162 line.equalsIgnoreCase( 163 INFO_PROMPT_NO_FIRST_LETTER_ANSWER.get().toString())) 164 { 165 LocalizableMessage message = ERR_PROMPTTM_USER_REJECTED.get(); 166 throw new CertificateException(message.toString()); 167 } 168 } catch (IOException ioe) {} 169 170 System.out.println(); 171 } 172 } 173 174 175 176 /** 177 * Retrieves the set of certificate authority certificates which are trusted 178 * for authenticating peers. 179 * 180 * @return An empty array, since we don't care what certificates are 181 * presented because we will always prompt the user. 182 */ 183 public X509Certificate[] getAcceptedIssuers() 184 { 185 return new X509Certificate[0]; 186 } 187} 188