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