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