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-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018 019import static org.opends.messages.ToolMessages.*; 020 021import java.io.BufferedReader; 022import java.io.IOException; 023import java.io.InputStreamReader; 024import java.security.cert.CertificateException; 025import java.security.cert.X509Certificate; 026import java.util.Date; 027 028import javax.net.ssl.TrustManager; 029import javax.net.ssl.X509TrustManager; 030 031import org.forgerock.i18n.LocalizableMessage; 032 033/** 034 * This class provides an implementation of an X.509 trust manager which will 035 * interactively prompt the user (via the CLI) whether a given certificate 036 * should be trusted. It should only be used by interactive command-line tools, 037 * since it will block until it gets a response from the user. 038 * <BR><BR> 039 * Note that this class is only intended for client-side use, and therefore may 040 * not be used by a server to determine whether a client certificate is trusted. 041 */ 042public class PromptTrustManager 043 implements X509TrustManager 044{ 045 /** The singleton trust manager array for this class. */ 046 private static TrustManager[] trustManagerArray = 047 new TrustManager[] { new PromptTrustManager() }; 048 049 /** Creates a new instance of this prompt trust manager. */ 050 private PromptTrustManager() 051 { 052 // No implementation is required. 053 } 054 055 /** 056 * Retrieves the trust manager array that should be used to initialize an SSL 057 * context in cases where the user should be interactively prompted about 058 * whether to trust the server certificate. 059 * 060 * @return The trust manager array that should be used to initialize an SSL 061 * context in cases where the user should be interactively prompted 062 * about whether to trust the server certificate. 063 */ 064 public static TrustManager[] getTrustManagers() 065 { 066 return trustManagerArray; 067 } 068 069 /** 070 * Determines whether an SSL client with the provided certificate chain should 071 * be trusted. This implementation is not intended for server-side use, and 072 * therefore this method will always throw an exception. 073 * 074 * @param chain The certificate chain for the SSL client. 075 * @param authType The authentication type based on the client certificate. 076 * 077 * @throws CertificateException To indicate that the provided client 078 * certificate is not trusted. 079 */ 080 @Override 081 public void checkClientTrusted(X509Certificate[] chain, String authType) 082 throws CertificateException 083 { 084 LocalizableMessage message = ERR_PROMPTTM_REJECTING_CLIENT_CERT.get(); 085 throw new CertificateException(message.toString()); 086 } 087 088 /** 089 * Determines whether an SSL server with the provided certificate chain should 090 * be trusted. In this case, the user will be interactively prompted as to 091 * whether the certificate should be trusted. 092 * 093 * @param chain The certificate chain for the SSL server. 094 * @param authType The key exchange algorithm used. 095 * 096 * @throws CertificateException If the user rejects the certificate. 097 */ 098 @Override 099 public void checkServerTrusted(X509Certificate[] chain, String authType) 100 throws CertificateException 101 { 102 if (chain == null || chain.length == 0) 103 { 104 System.out.println(WARN_PROMPTTM_NO_SERVER_CERT_CHAIN.get()); 105 } 106 else 107 { 108 Date currentDate = new Date(); 109 Date notAfterDate = chain[0].getNotAfter(); 110 Date notBeforeDate = chain[0].getNotBefore(); 111 112 if (currentDate.after(notAfterDate)) 113 { 114 System.err.println(WARN_PROMPTTM_CERT_EXPIRED.get(notAfterDate)); 115 } 116 else if (currentDate.before(notBeforeDate)) 117 { 118 System.err.println(WARN_PROMPTTM_CERT_NOT_YET_VALID.get(notBeforeDate)); 119 } 120 121 System.out.println(INFO_PROMPTTM_SERVER_CERT.get( 122 chain[0].getSubjectDN().getName(), 123 chain[0].getIssuerDN().getName(), 124 notBeforeDate, 125 notAfterDate)); 126 } 127 128 LocalizableMessage prompt = INFO_PROMPTTM_YESNO_PROMPT.get(); 129 BufferedReader reader = 130 new BufferedReader(new InputStreamReader(System.in)); 131 while (true) 132 { 133 try 134 { 135 System.out.print(prompt); 136 String line = reader.readLine().toLowerCase(); 137 if (line.equalsIgnoreCase( 138 INFO_PROMPT_YES_COMPLETE_ANSWER.get().toString()) || 139 line.equalsIgnoreCase( 140 INFO_PROMPT_YES_FIRST_LETTER_ANSWER.get().toString())) 141 { 142 // Returning without an exception is sufficient to consider the 143 // certificate trusted. 144 return; 145 } 146 if (line.equalsIgnoreCase( 147 INFO_PROMPT_NO_COMPLETE_ANSWER.get().toString()) || 148 line.equalsIgnoreCase( 149 INFO_PROMPT_NO_FIRST_LETTER_ANSWER.get().toString())) 150 { 151 LocalizableMessage message = ERR_PROMPTTM_USER_REJECTED.get(); 152 throw new CertificateException(message.toString()); 153 } 154 } catch (IOException ioe) {} 155 156 System.out.println(); 157 } 158 } 159 160 /** 161 * Retrieves the set of certificate authority certificates which are trusted 162 * for authenticating peers. 163 * 164 * @return An empty array, since we don't care what certificates are 165 * presented because we will always prompt the user. 166 */ 167 @Override 168 public X509Certificate[] getAcceptedIssuers() 169 { 170 return new X509Certificate[0]; 171 } 172}