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-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2015 ForgeRock AS. 016 */ 017 018package org.opends.quicksetup.ui; 019 020import static org.opends.messages.QuickSetupMessages.*; 021 022import java.awt.CardLayout; 023import java.awt.Component; 024import java.awt.Dimension; 025import java.awt.GridBagConstraints; 026import java.awt.GridBagLayout; 027import java.awt.event.ActionEvent; 028import java.awt.event.ActionListener; 029import java.awt.event.WindowAdapter; 030import java.awt.event.WindowEvent; 031import java.security.MessageDigest; 032import java.security.NoSuchAlgorithmException; 033import java.security.cert.CertificateEncodingException; 034import java.security.cert.X509Certificate; 035import java.text.DateFormat; 036import java.util.Date; 037import java.util.HashMap; 038import java.util.Map; 039 040import javax.naming.ldap.LdapName; 041import javax.naming.ldap.Rdn; 042import javax.swing.Box; 043import javax.swing.JButton; 044import javax.swing.JComboBox; 045import javax.swing.JComponent; 046import javax.swing.JDialog; 047import javax.swing.JEditorPane; 048import javax.swing.JFrame; 049import javax.swing.JLabel; 050import javax.swing.JPanel; 051import javax.swing.JScrollPane; 052import javax.swing.border.EmptyBorder; 053import javax.swing.event.HyperlinkEvent; 054import javax.swing.event.HyperlinkListener; 055 056import org.forgerock.i18n.LocalizableMessage; 057import org.forgerock.i18n.LocalizableMessageBuilder; 058import org.forgerock.i18n.slf4j.LocalizedLogger; 059import org.opends.quicksetup.UserDataCertificateException; 060import org.opends.quicksetup.event.MinimumSizeComponentListener; 061 062/** 063 * This class is used to present the user a certificate to the user in order 064 * it to be accepted. 065 */ 066public class CertificateDialog extends JDialog implements HyperlinkListener 067{ 068 /** 069 * The enumeration that defines the different answers that the user can 070 * provide for this dialog. 071 */ 072 public enum ReturnType 073 { 074 /** The user did not accept the certificate. */ 075 NOT_ACCEPTED, 076 /** The user accepted the certificate only for this session. */ 077 ACCEPTED_FOR_SESSION, 078 /** The user accepted the certificate permanently. */ 079 ACCEPTED_PERMANENTLY 080 } 081 private static final long serialVersionUID = -8989965057591475064L; 082 private ReturnType returnValue = ReturnType.NOT_ACCEPTED; 083 private UserDataCertificateException ce; 084 private JButton doNotAcceptButton; 085 private JComponent certificateDetails; 086 private JEditorPane explanationPane; 087 private boolean detailsAlreadyClicked; 088 private String explanationWithHideDetails; 089 private String explanationWithShowDetails; 090 091 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 092 093 /** 094 * Constructor of the certificate dialog. 095 * @param parent the parent frame for this dialog. 096 * @param ce the UserDataCertificateException we use to get the information 097 * about the certificate that was presented and the reason why it was 098 * rejected. 099 */ 100 public CertificateDialog(JFrame parent, UserDataCertificateException ce) 101 { 102 super(parent); 103 this.ce = ce; 104 setTitle(INFO_CERTIFICATE_DIALOG_TITLE.get().toString()); 105 getContentPane().add(createPanel()); 106 setModal(true); 107 pack(); 108 if (parent != null 109 && getPreferredSize().width > parent.getWidth()) 110 { 111 setPreferredSize(new Dimension(Math.max(parent.getWidth() - 20, 600), 112 getPreferredSize().height)); 113 } 114 pack(); 115 int minWidth = (int) getPreferredSize().getWidth(); 116 int minHeight = (int) getPreferredSize().getHeight(); 117 addComponentListener(new MinimumSizeComponentListener(this, minWidth, 118 minHeight)); 119 getRootPane().setDefaultButton(doNotAcceptButton); 120 121 addWindowListener(new WindowAdapter() 122 { 123 @Override 124 public void windowClosing(WindowEvent e) 125 { 126 doNotAccept(); 127 } 128 }); 129 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); 130 131 Utilities.centerOnComponent(this, parent); 132 } 133 134 /** 135 * Wheter the user accepted the certificate or not. 136 * @return the ReturnType object defining what the user chose to do with the 137 * certificate. 138 */ 139 public ReturnType getUserAnswer() 140 { 141 return returnValue; 142 } 143 144 /** 145 * Implements HyperlinkListener. When the user clicks on a link we assume 146 * that is the show details/hide details and we update the visible components 147 * accordingly. 148 * 149 * @param e the HyperlinkEvent. 150 */ 151 @Override 152 public void hyperlinkUpdate(HyperlinkEvent e) 153 { 154 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) 155 { 156 boolean detailsVisible = !certificateDetails.isVisible(); 157 explanationPane.setText(detailsVisible? 158 explanationWithHideDetails:explanationWithShowDetails); 159 certificateDetails.setVisible(detailsVisible); 160 if (detailsVisible && !detailsAlreadyClicked) 161 { 162 detailsAlreadyClicked = true; 163 pack(); 164 } 165 } 166 } 167 168 /** 169 * Creates and returns the panel of the dialog. 170 * @return the panel of the dialog. 171 */ 172 private JPanel createPanel() 173 { 174 GridBagConstraints gbc = new GridBagConstraints(); 175 176 JPanel contentPanel = new JPanel(new GridBagLayout()); 177 contentPanel.setBackground(UIFactory.DEFAULT_BACKGROUND); 178 gbc.anchor = GridBagConstraints.NORTHWEST; 179 gbc.insets = UIFactory.getEmptyInsets(); 180 gbc.fill = GridBagConstraints.BOTH; 181 gbc.gridwidth = GridBagConstraints.REMAINDER; 182 gbc.weightx = 1.0; 183 184 JPanel topPanel = new JPanel(new GridBagLayout()); 185 topPanel.setBorder(UIFactory.DIALOG_PANEL_BORDER); 186 topPanel.setBackground(UIFactory.CURRENT_STEP_PANEL_BACKGROUND); 187 188 gbc.weighty = 0.0; 189 gbc.insets = UIFactory.getCurrentStepPanelInsets(); 190 topPanel.add(createTitlePanel(), gbc); 191 gbc.insets.top = UIFactory.TOP_INSET_INSTRUCTIONS_SUBPANEL; 192 topPanel.add(createTextPane(), gbc); 193 certificateDetails = createCertificateDetailsPane(); 194 gbc.insets.top = 0; 195 gbc.insets.bottom = 0; 196 topPanel.add(Box.createHorizontalStrut( 197 certificateDetails.getPreferredSize().width), gbc); 198 gbc.insets.top = 0; 199 gbc.weighty = 1.0; 200 JPanel auxPanel = UIFactory.makeJPanel(); 201 auxPanel.setLayout(new GridBagLayout()); 202 gbc.weightx = 0.0; 203 gbc.insets = UIFactory.getEmptyInsets(); 204 gbc.gridwidth = GridBagConstraints.RELATIVE; 205 auxPanel.add(Box.createVerticalStrut(100), gbc); 206 gbc.weightx = 1.0; 207 gbc.gridwidth = GridBagConstraints.REMAINDER; 208 auxPanel.add(certificateDetails, gbc); 209 gbc.insets = UIFactory.getCurrentStepPanelInsets(); 210 gbc.insets.bottom = UIFactory.TOP_INSET_INPUT_SUBPANEL; 211 topPanel.add(auxPanel, gbc); 212 certificateDetails.setVisible(false); 213 gbc.weighty = 0.2; 214 gbc.insets = UIFactory.getEmptyInsets(); 215 topPanel.add(Box.createVerticalGlue(), gbc); 216 contentPanel.add(topPanel, gbc); 217 gbc.weighty = 0.0; 218 gbc.insets = UIFactory.getButtonsPanelInsets(); 219 gbc.fill = GridBagConstraints.HORIZONTAL; 220 contentPanel.add(createButtonsPanel(), gbc); 221 222 return contentPanel; 223 } 224 225 /** 226 * Creates and returns the title sub panel. 227 * @return the title sub panel. 228 */ 229 private Component createTitlePanel() 230 { 231 JPanel titlePanel = UIFactory.makeJPanel(); 232 titlePanel.setLayout(new GridBagLayout()); 233 GridBagConstraints gbc = new GridBagConstraints(); 234 gbc.anchor = GridBagConstraints.NORTHWEST; 235 gbc.fill = GridBagConstraints.BOTH; 236 gbc.weightx = 0.0; 237 gbc.gridwidth = GridBagConstraints.RELATIVE; 238 239 LocalizableMessage title = INFO_CERTIFICATE_TITLE.get(); 240 JLabel l = 241 UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, title, 242 UIFactory.TextStyle.TITLE); 243 l.setOpaque(false); 244 titlePanel.add(l, gbc); 245 246 gbc.gridwidth = GridBagConstraints.RELATIVE; 247 gbc.anchor = GridBagConstraints.NORTHWEST; 248 gbc.weightx = 1.0; 249 gbc.gridwidth = GridBagConstraints.REMAINDER; 250 gbc.insets.left = 0; 251 gbc.weightx = 1.0; 252 gbc.gridwidth = GridBagConstraints.REMAINDER; 253 titlePanel.add(Box.createHorizontalGlue(), gbc); 254 255 return titlePanel; 256 } 257 258 /** 259 * Creates and returns the text sub panel. 260 * @return the text sub panel. 261 */ 262 private Component createTextPane() 263 { 264 LocalizableMessage text; 265 if (ce.getType() == UserDataCertificateException.Type.NOT_TRUSTED) 266 { 267 text = INFO_CERTIFICATE_NOT_TRUSTED_TEXT.get( 268 ce.getHost(), ce.getPort(), 269 ce.getHost(), ce.getPort()); 270 } 271 else 272 { 273 text = INFO_CERTIFICATE_NAME_MISMATCH_TEXT.get( 274 ce.getHost(), ce.getPort(), 275 ce.getHost(), 276 ce.getHost(), ce.getPort(), 277 ce.getHost(), ce.getPort()); 278 } 279 JPanel p = UIFactory.makeJPanel(); 280 p.setLayout(new GridBagLayout()); 281 GridBagConstraints gbc = new GridBagConstraints(); 282 gbc.gridwidth = GridBagConstraints.RELATIVE; 283 gbc.anchor = GridBagConstraints.NORTHWEST; 284 p.add(UIFactory.makeJLabel(UIFactory.IconType.WARNING_LARGE, null, 285 UIFactory.TextStyle.NO_STYLE), gbc); 286 gbc.weightx = 1.0; 287 gbc.gridwidth = GridBagConstraints.REMAINDER; 288 gbc.fill = GridBagConstraints.BOTH; 289 gbc.insets.left = UIFactory.LEFT_INSET_PRIMARY_FIELD; 290 gbc.insets.bottom = 0; 291 explanationPane = UIFactory.makeHtmlPane(null, UIFactory.INSTRUCTIONS_FONT); 292 explanationPane.setOpaque(false); 293 explanationPane.setEditable(false); 294 explanationPane.addHyperlinkListener(this); 295 p.add(explanationPane, gbc); 296 if (ce.getChain() != null && ce.getChain().length > 0) 297 { 298 LocalizableMessageBuilder mb = new LocalizableMessageBuilder(); 299 mb.append(text); 300 mb.append(INFO_CERTIFICATE_SHOW_DETAILS_TEXT.get()); 301 explanationWithShowDetails = UIFactory.applyFontToHtml( 302 mb.toString(), UIFactory.INSTRUCTIONS_FONT); 303 LocalizableMessageBuilder mb2 = new LocalizableMessageBuilder(); 304 mb2.append(text); 305 mb2.append(INFO_CERTIFICATE_HIDE_DETAILS_TEXT.get()); 306 explanationWithHideDetails = UIFactory.applyFontToHtml( 307 mb2.toString(), UIFactory.INSTRUCTIONS_FONT); 308 309 explanationPane.setText(explanationWithShowDetails); 310 } 311 else 312 { 313 explanationPane.setText(text.toString()); 314 } 315 return p; 316 } 317 318 /** 319 * Creates and returns the buttons DO NOT ACCEPT/ACCEPT FOR THIS SESSION/ 320 * ACCEPT PERMANENTLY sub panel. 321 * @return the buttons DO NOT ACCEPT/ACCEPT FOR THIS SESSION/ACCEPT 322 * PERMANENTLY sub panel. 323 */ 324 private Component createButtonsPanel() 325 { 326 JPanel buttonsPanel = UIFactory.makeJPanel(); 327 buttonsPanel.setLayout(new GridBagLayout()); 328 GridBagConstraints gbc = new GridBagConstraints(); 329 gbc.fill = GridBagConstraints.HORIZONTAL; 330 gbc.gridwidth = 4; 331 gbc.insets = UIFactory.getEmptyInsets(); 332 gbc.insets.left = UIFactory.getCurrentStepPanelInsets().left; 333 buttonsPanel.add(UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, 334 null, UIFactory.TextStyle.NO_STYLE), gbc); 335 gbc.weightx = 1.0; 336 gbc.gridwidth--; 337 gbc.insets.left = 0; 338 buttonsPanel.add(Box.createHorizontalGlue(), gbc); 339 gbc.gridwidth = 3; 340 gbc.fill = GridBagConstraints.NONE; 341 gbc.weightx = 0.0; 342 JButton acceptSessionButton = UIFactory.makeJButton( 343 INFO_CERTIFICATE_DIALOG_ACCEPT_FOR_SESSION_BUTTON_LABEL.get(), 344 INFO_CERTIFICATE_DIALOG_ACCEPT_FOR_SESSION_BUTTON_TOOLTIP.get()); 345 buttonsPanel.add(acceptSessionButton, gbc); 346 acceptSessionButton.addActionListener(new ActionListener() { 347 @Override 348 public void actionPerformed(ActionEvent ev) { 349 acceptForSession(); 350 } 351 }); 352 353 gbc.gridwidth = GridBagConstraints.RELATIVE; 354 gbc.insets.left = UIFactory.HORIZONTAL_INSET_BETWEEN_BUTTONS; 355 JButton acceptPermanentlyButton = UIFactory.makeJButton( 356 INFO_CERTIFICATE_DIALOG_ACCEPT_PERMANENTLY_BUTTON_LABEL.get(), 357 INFO_CERTIFICATE_DIALOG_ACCEPT_PERMANENTLY_BUTTON_TOOLTIP.get()); 358 buttonsPanel.add(acceptPermanentlyButton, gbc); 359 acceptPermanentlyButton.addActionListener(new ActionListener() { 360 @Override 361 public void actionPerformed(ActionEvent ev) { 362 acceptPermanently(); 363 } 364 }); 365 366 gbc.gridwidth = GridBagConstraints.REMAINDER; 367 doNotAcceptButton = 368 UIFactory.makeJButton( 369 INFO_CERTIFICATE_DIALOG_DO_NOT_ACCEPT_BUTTON_LABEL.get(), 370 INFO_CERTIFICATE_DIALOG_DO_NOT_ACCEPT_BUTTON_TOOLTIP.get()); 371 buttonsPanel.add(doNotAcceptButton, gbc); 372 doNotAcceptButton.addActionListener(new ActionListener() 373 { 374 @Override 375 public void actionPerformed(ActionEvent ev) 376 { 377 doNotAccept(); 378 } 379 }); 380 381 return buttonsPanel; 382 } 383 384 /** 385 * Creates the panel containing a representation of the certificate chain. 386 * @return the panel containing a representation of the certificate chain. 387 */ 388 private JComponent createCertificateDetailsPane() 389 { 390 JPanel p = UIFactory.makeJPanel(); 391 p.setLayout(new GridBagLayout()); 392 if (ce.getChain() != null && ce.getChain().length > 0) 393 { 394 final JComboBox combo = new JComboBox(); 395 combo.setToolTipText( 396 INFO_CERTIFICATE_CHAIN_COMBO_TOOLTIP.get().toString()); 397 final CardLayout cl = new CardLayout(); 398 final JPanel cardPanel = new JPanel(cl); 399 final Map<String, JPanel> hmPanels = new HashMap<>(); 400 401 LocalizableMessage[] labels = 402 { 403 INFO_CERTIFICATE_SUBJECT_LABEL.get(), 404 INFO_CERTIFICATE_ISSUED_BY_LABEL.get(), 405 INFO_CERTIFICATE_VALID_FROM_LABEL.get(), 406 INFO_CERTIFICATE_EXPIRES_ON_LABEL.get(), 407 INFO_CERTIFICATE_TYPE_LABEL.get(), 408 INFO_CERTIFICATE_SERIAL_NUMBER_LABEL.get(), 409 INFO_CERTIFICATE_MD5_FINGERPRINT_LABEL.get(), 410 INFO_CERTIFICATE_SHA1_FINGERPRINT_LABEL.get() 411 }; 412 413 for (int i=0; i<ce.getChain().length; i++) 414 { 415 X509Certificate cert = ce.getChain()[i]; 416 JComponent[] components = 417 { 418 createSubjectComponent(cert), 419 createIssuedByComponent(cert), 420 createValidFromComponent(cert), 421 createExpiresOnComponent(cert), 422 createTypeComponent(cert), 423 createSerialNumberComponent(cert), 424 createMD5FingerprintComponent(cert), 425 createSHA1FingerprintComponent(cert) 426 }; 427 JPanel certPanel = UIFactory.makeJPanel(); 428 certPanel.setLayout(new GridBagLayout()); 429 GridBagConstraints gbc = new GridBagConstraints(); 430 gbc.anchor = GridBagConstraints.NORTHWEST; 431 gbc.fill = GridBagConstraints.HORIZONTAL; 432 433 for (int j=0; j<labels.length; j++) 434 { 435 JLabel l = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, 436 labels[j], UIFactory.TextStyle.PRIMARY_FIELD_VALID); 437 438 l.setLabelFor(components[j]); 439 if (j > 0) 440 { 441 gbc.insets.top = UIFactory.TOP_INSET_SECONDARY_FIELD; 442 } 443 gbc.gridwidth = GridBagConstraints.RELATIVE; 444 gbc.weightx = 0.0; 445 gbc.insets.left = 0; 446 certPanel.add(l, gbc); 447 gbc.gridwidth = GridBagConstraints.REMAINDER; 448 gbc.weightx = 1.0; 449 gbc.insets.left = UIFactory.LEFT_INSET_SECONDARY_FIELD; 450 certPanel.add(components[j], gbc); 451 } 452 String name = getName(cert); 453 hmPanels.put(name, certPanel); 454 cardPanel.add(name, certPanel); 455 combo.addItem(name); 456 } 457 GridBagConstraints gbc = new GridBagConstraints(); 458 if (ce.getChain().length == 1) 459 { 460 gbc.gridwidth = GridBagConstraints.REMAINDER; 461 gbc.weightx = 1.0; 462 gbc.fill = GridBagConstraints.BOTH; 463 p.add(cardPanel, gbc); 464 465 gbc.weighty = 1.0; 466 p.add(Box.createVerticalGlue(), gbc); 467 } 468 else 469 { 470 gbc.anchor = GridBagConstraints.WEST; 471 gbc.gridwidth = 3; 472 gbc.fill = GridBagConstraints.HORIZONTAL; 473 JPanel auxPanel = UIFactory.makeJPanel(); 474 auxPanel.setLayout(new GridBagLayout()); 475 JLabel l = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, 476 INFO_CERTIFICATE_CHAIN_LABEL.get(), 477 UIFactory.TextStyle.PRIMARY_FIELD_VALID); 478 auxPanel.add(l, gbc); 479 gbc.gridwidth = GridBagConstraints.RELATIVE; 480 gbc.insets.left = UIFactory.LEFT_INSET_SECONDARY_FIELD; 481 auxPanel.add(combo, gbc); 482 l.setLabelFor(combo); 483 gbc.gridwidth = GridBagConstraints.REMAINDER; 484 gbc.insets.left = 0; 485 gbc.weightx = 1.0; 486 auxPanel.add(Box.createHorizontalGlue(), gbc); 487 488 p.add(auxPanel, gbc); 489 490 gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD; 491 gbc.fill = GridBagConstraints.BOTH; 492 p.add(cardPanel, gbc); 493 494 gbc.weighty = 1.0; 495 p.add(Box.createVerticalGlue(), gbc); 496 } 497 498 combo.addActionListener(new ActionListener() 499 { 500 @Override 501 public void actionPerformed(ActionEvent ev) 502 { 503 String selectedItem = (String)combo.getSelectedItem(); 504 cl.show(hmPanels.get(selectedItem), selectedItem); 505 } 506 }); 507 } 508 JScrollPane scroll = new JScrollPane(p); 509 scroll.setViewportBorder(new EmptyBorder(0, 0, 0, 0)); 510 scroll.setOpaque(false); 511 scroll.getViewport().setOpaque(false); 512 scroll.setPreferredSize(new Dimension(scroll.getPreferredSize().width, 513 175)); 514 return scroll; 515 } 516 517 private JComponent createSubjectComponent(X509Certificate cert) 518 { 519 LocalizableMessage dn = LocalizableMessage.raw(cert.getSubjectX500Principal().getName()); 520 return makeValueLabel(dn); 521 } 522 523 private JComponent createIssuedByComponent(X509Certificate cert) 524 { 525 LocalizableMessage dn = LocalizableMessage.raw(cert.getIssuerX500Principal().getName()); 526 return makeValueLabel(dn); 527 } 528 529 private JComponent createValidFromComponent(X509Certificate cert) 530 { 531 JComponent c; 532 533 Date date = cert.getNotBefore(); 534 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, 535 DateFormat.SHORT); 536 LocalizableMessage value = LocalizableMessage.raw(df.format(date)); 537 long t1 = System.currentTimeMillis(); 538 long t2 = date.getTime(); 539 boolean isNotValidYet = t1 < t2; 540 541 if (isNotValidYet) 542 { 543 c = UIFactory.makeJLabel(UIFactory.IconType.ERROR, 544 INFO_CERTIFICATE_NOT_VALID_YET.get(value), 545 UIFactory.TextStyle.SECONDARY_FIELD_INVALID); 546 } 547 else 548 { 549 c = makeValueLabel(value); 550 } 551 return c; 552 } 553 554 555 private JComponent createExpiresOnComponent(X509Certificate cert) 556 { 557 JComponent c; 558 559 Date date = cert.getNotAfter(); 560 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, 561 DateFormat.SHORT); 562 LocalizableMessage value = LocalizableMessage.raw(df.format(date)); 563 long t1 = System.currentTimeMillis(); 564 long t2 = date.getTime(); 565 boolean isExpired = t1 > t2; 566 567 if (isExpired) 568 { 569 c = UIFactory.makeJLabel(UIFactory.IconType.ERROR, 570 INFO_CERTIFICATE_EXPIRED.get(value), 571 UIFactory.TextStyle.SECONDARY_FIELD_INVALID); 572 } 573 else 574 { 575 c = makeValueLabel(value); 576 } 577 return c; 578 } 579 580 581 private JComponent createTypeComponent(X509Certificate cert) 582 { 583 LocalizableMessage type = LocalizableMessage.raw(cert.getType()); 584 return makeValueLabel(type); 585 } 586 587 private JComponent createSerialNumberComponent(X509Certificate cert) 588 { 589 LocalizableMessage serialNumber = LocalizableMessage.raw(String.valueOf(cert.getSerialNumber())); 590 return makeValueLabel(serialNumber); 591 } 592 593 594 /** 595 * Returns the LocalizableMessage representation of the SHA1 fingerprint. 596 * @param cert the certificate object. 597 * @return the LocalizableMessage representation of the SHA1 fingerprint. 598 */ 599 public static LocalizableMessage getSHA1FingerPrint(X509Certificate cert) 600 { 601 return getFingerPrint(cert, "SHA1"); 602 } 603 604 /** 605 * Returns the LocalizableMessage representation of the MD5 fingerprint. 606 * @param cert the certificate object. 607 * @return the LocalizableMessage representation of the MD5 fingerprint. 608 */ 609 public static LocalizableMessage getMD5FingerPrint(X509Certificate cert) 610 { 611 return getFingerPrint(cert, "MD5"); 612 } 613 614 private static LocalizableMessage getFingerPrint(X509Certificate cert, String algorithm) 615 { 616 try { 617 MessageDigest md = MessageDigest.getInstance(algorithm); 618 byte[] b = md.digest(cert.getEncoded()); 619 StringBuilder sb = new StringBuilder(); 620 for (int i = 0; i < b.length; i++) 621 { 622 if (i > 0) 623 { 624 sb.append(":"); 625 } 626 sb.append(Integer.toHexString(b[i] & 0xFF)); 627 } 628 return LocalizableMessage.raw(sb); 629 } 630 catch (NoSuchAlgorithmException nsae) { 631 logger.warn(LocalizableMessage.raw(algorithm + " algorithm not supported: " + nsae, nsae)); 632 return null; 633 } 634 catch (CertificateEncodingException cee) { 635 logger.warn(LocalizableMessage.raw("Certificate encoding exception: "+cee, cee)); 636 return null; 637 } 638 } 639 640 private JComponent createSHA1FingerprintComponent(X509Certificate cert) 641 { 642 return UIFactory.makeTextPane(getSHA1FingerPrint(cert), 643 UIFactory.TextStyle.SECONDARY_FIELD_VALID); 644 } 645 646 private JComponent createMD5FingerprintComponent(X509Certificate cert) 647 { 648 return UIFactory.makeTextPane(getMD5FingerPrint(cert), 649 UIFactory.TextStyle.SECONDARY_FIELD_VALID); 650 } 651 652 private JLabel makeValueLabel(LocalizableMessage value) 653 { 654 if (value == null) 655 { 656 value = INFO_NOT_AVAILABLE_LABEL.get(); 657 } 658 return UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, value, 659 UIFactory.TextStyle.SECONDARY_FIELD_VALID); 660 } 661 662 private String getName(X509Certificate cert) 663 { 664 String name = cert.getSubjectX500Principal().getName(); 665 try 666 { 667 LdapName dn = new LdapName(name); 668 Rdn rdn = dn.getRdn(0); 669 return rdn.getValue().toString(); 670 } 671 catch (Throwable t) 672 { 673 logger.warn(LocalizableMessage.raw("Error parsing subject dn: "+ 674 cert.getSubjectX500Principal(), t)); 675 return name; 676 } 677 } 678 679 /** Method called when user clicks on ok. */ 680 private void acceptForSession() 681 { 682 returnValue = ReturnType.ACCEPTED_FOR_SESSION; 683 dispose(); 684 } 685 686 /** Method called when user clicks on cancel. */ 687 private void doNotAccept() 688 { 689 returnValue = ReturnType.NOT_ACCEPTED; 690 dispose(); 691 } 692 693 /** Method called when user clicks on ok. */ 694 private void acceptPermanently() 695 { 696 returnValue = ReturnType.ACCEPTED_PERMANENTLY; 697 dispose(); 698 } 699}