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 2007-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2011-2016 ForgeRock AS. 016 */ 017package org.opends.server.backends; 018 019import static org.forgerock.util.Reject.*; 020import static org.opends.messages.BackendMessages.*; 021import static org.opends.server.config.ConfigConstants.*; 022import static org.opends.server.util.ServerConstants.*; 023import static org.opends.server.util.StaticUtils.*; 024 025import java.io.BufferedReader; 026import java.io.File; 027import java.io.FileInputStream; 028import java.io.FileOutputStream; 029import java.io.FileReader; 030import java.io.FileWriter; 031import java.io.IOException; 032import java.io.PrintWriter; 033import java.net.UnknownHostException; 034import java.security.Key; 035import java.security.KeyStore; 036import java.security.KeyStoreException; 037import java.security.cert.Certificate; 038import java.util.Collections; 039import java.util.Iterator; 040import java.util.LinkedHashMap; 041import java.util.List; 042import java.util.Random; 043import java.util.Set; 044import java.util.SortedSet; 045 046import javax.naming.ldap.Rdn; 047import javax.net.ssl.KeyManager; 048import javax.net.ssl.KeyManagerFactory; 049import javax.net.ssl.TrustManager; 050import javax.net.ssl.TrustManagerFactory; 051 052import org.forgerock.i18n.LocalizableMessage; 053import org.forgerock.i18n.slf4j.LocalizedLogger; 054import org.forgerock.opendj.config.server.ConfigChangeResult; 055import org.forgerock.opendj.config.server.ConfigException; 056import org.forgerock.opendj.ldap.AVA; 057import org.forgerock.opendj.ldap.ByteString; 058import org.forgerock.opendj.ldap.ConditionResult; 059import org.forgerock.opendj.ldap.DN; 060import org.forgerock.opendj.ldap.RDN; 061import org.forgerock.opendj.ldap.ResultCode; 062import org.forgerock.opendj.ldap.SearchScope; 063import org.forgerock.opendj.ldap.schema.AttributeType; 064import org.forgerock.util.Reject; 065import org.opends.server.admin.server.ConfigurationChangeListener; 066import org.opends.server.admin.std.server.TrustStoreBackendCfg; 067import org.opends.server.api.Backend; 068import org.opends.server.core.AddOperation; 069import org.opends.server.core.DeleteOperation; 070import org.opends.server.core.DirectoryServer; 071import org.opends.server.core.ModifyDNOperation; 072import org.opends.server.core.ModifyOperation; 073import org.opends.server.core.SearchOperation; 074import org.opends.server.core.ServerContext; 075import org.opends.server.types.Attribute; 076import org.opends.server.types.AttributeBuilder; 077import org.opends.server.types.Attributes; 078import org.opends.server.types.BackupConfig; 079import org.opends.server.types.BackupDirectory; 080import org.opends.server.types.DirectoryException; 081import org.opends.server.types.Entry; 082import org.opends.server.types.FilePermission; 083import org.opends.server.types.IndexType; 084import org.opends.server.types.InitializationException; 085import org.opends.server.types.LDIFExportConfig; 086import org.opends.server.types.LDIFImportConfig; 087import org.opends.server.types.LDIFImportResult; 088import org.opends.server.types.ObjectClass; 089import org.opends.server.types.RestoreConfig; 090import org.opends.server.types.SearchFilter; 091import org.opends.server.util.CertificateManager; 092import org.opends.server.util.Platform.KeyType; 093import org.opends.server.util.SetupUtils; 094 095/** 096 * This class defines a backend used to provide an LDAP view of public keys 097 * stored in a key store. 098 */ 099public class TrustStoreBackend extends Backend<TrustStoreBackendCfg> 100 implements ConfigurationChangeListener<TrustStoreBackendCfg> 101{ 102 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 103 104 105 106 /** The current configuration state. */ 107 private TrustStoreBackendCfg configuration; 108 109 /** The DN for the base entry. */ 110 private DN baseDN; 111 112 /** The set of base DNs for this backend. */ 113 private DN[] baseDNs; 114 115 /** The base entry. */ 116 private Entry baseEntry; 117 118 /** The PIN needed to access the trust store backing file. */ 119 private char[] trustStorePIN; 120 121 /** The path to the trust store backing file. */ 122 private String trustStoreFile; 123 124 /** The type of trust store backing file to use. */ 125 private String trustStoreType; 126 127 /** The certificate manager for the trust store. */ 128 private CertificateManager certificateManager; 129 130 131 132 /** 133 * Creates a new backend. All backend 134 * implementations must implement a default constructor that use 135 * <CODE>super()</CODE> to invoke this constructor. 136 */ 137 public TrustStoreBackend() 138 { 139 super(); 140 141 // Perform all initialization in initializeBackend. 142 } 143 144 /** {@inheritDoc} */ 145 @Override 146 public void configureBackend(TrustStoreBackendCfg config, ServerContext serverContext) throws ConfigException 147 { 148 Reject.ifNull(config); 149 configuration = config; 150 } 151 152 /** {@inheritDoc} */ 153 @Override 154 public void openBackend() throws ConfigException, InitializationException 155 { 156 DN configEntryDN = configuration.dn(); 157 158 // Create the set of base DNs that we will handle. In this case, it's just 159 // the DN of the base trust store entry. 160 SortedSet<DN> baseDNSet = configuration.getBaseDN(); 161 if (baseDNSet.size() != 1) 162 { 163 throw new InitializationException(ERR_TRUSTSTORE_REQUIRES_ONE_BASE_DN.get(configEntryDN)); 164 } 165 baseDN = baseDNSet.first(); 166 baseDNs = new DN[] {baseDN}; 167 168 // Get the path to the trust store file. 169 trustStoreFile = configuration.getTrustStoreFile(); 170 171 172 // Get the trust store type. If none is specified, then use the default 173 // type. 174 trustStoreType = configuration.getTrustStoreType(); 175 if (trustStoreType == null) 176 { 177 trustStoreType = KeyStore.getDefaultType(); 178 } 179 180 try 181 { 182 KeyStore.getInstance(trustStoreType); 183 } 184 catch (KeyStoreException kse) 185 { 186 logger.traceException(kse); 187 throw new InitializationException(ERR_TRUSTSTORE_INVALID_TYPE.get( 188 trustStoreType, configEntryDN, getExceptionMessage(kse))); 189 } 190 191 192 // Get the PIN needed to access the contents of the trust store file. We 193 // will offer several places to look for the PIN, and we will do so in the 194 // following order: 195 // - In a specified Java property 196 // - In a specified environment variable 197 // - In a specified file on the server filesystem. 198 // - As the value of a configuration attribute. 199 // In any case, the PIN must be in the clear. If no PIN is provided, then 200 // it will be assumed that none is required to access the information in the 201 // trust store. 202 String pinProperty = configuration.getTrustStorePinProperty(); 203 if (pinProperty == null) 204 { 205 String pinEnVar = configuration.getTrustStorePinEnvironmentVariable(); 206 if (pinEnVar == null) 207 { 208 String pinFilePath = configuration.getTrustStorePinFile(); 209 if (pinFilePath == null) 210 { 211 String pinStr = configuration.getTrustStorePin(); 212 if (pinStr == null) 213 { 214 // This should be an Error. Otherwise, programs fails. 215 // Is there a Unit Test? 216 trustStorePIN = null; 217 } 218 else 219 { 220 trustStorePIN = pinStr.toCharArray(); 221 } 222 } 223 else 224 { 225 File pinFile = getFileForPath(pinFilePath); 226 if (! pinFile.exists()) 227 { 228 try 229 { 230 // Generate a PIN. 231 trustStorePIN = createKeystorePassword(); 232 233 // Store the PIN in the pin file. 234 createPINFile(pinFile.getPath(), new String(trustStorePIN)); 235 } 236 catch (Exception e) 237 { 238 throw new InitializationException( 239 ERR_TRUSTSTORE_PIN_FILE_CANNOT_CREATE.get(pinFilePath, configEntryDN)); 240 } 241 } 242 else 243 { 244 String pinStr; 245 246 BufferedReader br = null; 247 try 248 { 249 br = new BufferedReader(new FileReader(pinFile)); 250 pinStr = br.readLine(); 251 } 252 catch (IOException ioe) 253 { 254 LocalizableMessage message = ERR_TRUSTSTORE_PIN_FILE_CANNOT_READ. 255 get(pinFilePath, configEntryDN, getExceptionMessage(ioe)); 256 throw new InitializationException(message, ioe); 257 } 258 finally 259 { 260 close(br); 261 } 262 263 if (pinStr == null) 264 { 265 throw new InitializationException( 266 ERR_TRUSTSTORE_PIN_FILE_EMPTY.get(pinFilePath, configEntryDN)); 267 } 268 trustStorePIN = pinStr.toCharArray(); 269 } 270 } 271 } 272 else 273 { 274 String pinStr = System.getenv(pinEnVar); 275 if (pinStr == null) 276 { 277 throw new InitializationException( 278 ERR_TRUSTSTORE_PIN_ENVAR_NOT_SET.get(pinProperty, configEntryDN)); 279 } 280 trustStorePIN = pinStr.toCharArray(); 281 } 282 } 283 else 284 { 285 String pinStr = System.getProperty(pinProperty); 286 if (pinStr == null) 287 { 288 throw new InitializationException(ERR_TRUSTSTORE_PIN_PROPERTY_NOT_SET.get(pinProperty, configEntryDN)); 289 } 290 trustStorePIN = pinStr.toCharArray(); 291 } 292 293 // Create a certificate manager. 294 certificateManager = 295 new CertificateManager(getFileForPath(trustStoreFile).getPath(), 296 trustStoreType, 297 new String(trustStorePIN)); 298 299 // Generate a self-signed certificate, if there is none. 300 generateInstanceCertificateIfAbsent(); 301 302 // Construct the trust store base entry. 303 LinkedHashMap<ObjectClass,String> objectClasses = new LinkedHashMap<>(2); 304 objectClasses.put(DirectoryServer.getTopObjectClass(), OC_TOP); 305 306 ObjectClass branchOC = 307 DirectoryServer.getObjectClass("ds-cfg-branch", true); 308 objectClasses.put(branchOC, "ds-cfg-branch"); 309 310 LinkedHashMap<AttributeType,List<Attribute>> userAttrs = new LinkedHashMap<>(1); 311 for (AVA ava : baseDN.rdn()) 312 { 313 AttributeType attrType = ava.getAttributeType(); 314 userAttrs.put(attrType, Attributes.createAsList(attrType, ava.getAttributeValue())); 315 } 316 317 baseEntry = new Entry(baseDN, objectClasses, userAttrs, null); 318 319 // Register this as a change listener. 320 configuration.addTrustStoreChangeListener(this); 321 322 323 // Register the trust store base as a private suffix. 324 try 325 { 326 DirectoryServer.registerBaseDN(baseDN, this, true); 327 } 328 catch (Exception e) 329 { 330 logger.traceException(e); 331 throw new InitializationException(ERR_BACKEND_CANNOT_REGISTER_BASEDN.get(baseDN, e), e); 332 } 333 } 334 335 /** {@inheritDoc} */ 336 @Override 337 public void closeBackend() 338 { 339 configuration.addTrustStoreChangeListener(this); 340 341 try 342 { 343 DirectoryServer.deregisterBaseDN(baseDN); 344 } 345 catch (Exception e) 346 { 347 logger.traceException(e); 348 } 349 } 350 351 /** {@inheritDoc} */ 352 @Override 353 public DN[] getBaseDNs() 354 { 355 return baseDNs; 356 } 357 358 /** {@inheritDoc} */ 359 @Override 360 public long getEntryCount() 361 { 362 int numEntries = 1; 363 364 try 365 { 366 String[] aliases = certificateManager.getCertificateAliases(); 367 if (aliases != null) 368 { 369 numEntries += aliases.length; 370 } 371 } 372 catch (KeyStoreException e) 373 { 374 logger.traceException(e); 375 } 376 377 return numEntries; 378 } 379 380 /** {@inheritDoc} */ 381 @Override 382 public boolean isIndexed(AttributeType attributeType, IndexType indexType) 383 { 384 // All searches in this backend will always be considered indexed. 385 return true; 386 } 387 388 /** {@inheritDoc} */ 389 @Override 390 public Entry getEntry(DN entryDN) throws DirectoryException 391 { 392 // If the requested entry was null, then throw an exception. 393 if (entryDN == null) 394 { 395 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 396 ERR_BACKEND_GET_ENTRY_NULL.get(getBackendID())); 397 } 398 399 400 // If the requested entry was the backend base entry, then retrieve it. 401 if (entryDN.equals(baseDN)) 402 { 403 return baseEntry.duplicate(true); 404 } 405 406 407 // See if the requested entry was one level below the backend base entry. 408 // If so, then it must point to a trust store entry. 409 DN parentDN = DirectoryServer.getParentDNInSuffix(entryDN); 410 if (parentDN != null && parentDN.equals(baseDN)) 411 { 412 try 413 { 414 return getCertEntry(entryDN); 415 } 416 catch (DirectoryException e) 417 { 418 logger.traceException(e); 419 } 420 } 421 return null; 422 } 423 424 425 426 /** 427 * Generates an entry for a certificate based on the provided DN. The 428 * DN must contain an RDN component that specifies the alias of the 429 * certificate, and that certificate alias must exist in the key store. 430 * 431 * @param entryDN The DN of the certificate to retrieve. 432 * 433 * @return The requested certificate entry. 434 * 435 * @throws DirectoryException If the specified alias does not exist, or if 436 * the DN does not specify any alias. 437 */ 438 private Entry getCertEntry(DN entryDN) 439 throws DirectoryException 440 { 441 // Make sure that the DN specifies a certificate alias. 442 AttributeType t = DirectoryServer.getAttributeType(ATTR_CRYPTO_KEY_ID); 443 ByteString v = entryDN.rdn().getAttributeValue(t); 444 if (v == null) 445 { 446 LocalizableMessage message = ERR_TRUSTSTORE_DN_DOES_NOT_SPECIFY_CERTIFICATE.get(entryDN); 447 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, baseDN, null); 448 } 449 450 String certAlias = v.toString(); 451 ByteString certValue; 452 try 453 { 454 Certificate cert = certificateManager.getCertificate(certAlias); 455 if (cert == null) 456 { 457 LocalizableMessage message = ERR_TRUSTSTORE_CERTIFICATE_NOT_FOUND.get(entryDN, certAlias); 458 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); 459 } 460 certValue = ByteString.wrap(cert.getEncoded()); 461 } 462 catch (Exception e) 463 { 464 logger.traceException(e); 465 466 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_RETRIEVE_CERT.get( 467 certAlias, trustStoreFile, e.getMessage()); 468 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); 469 } 470 471 // Construct the certificate entry to return. 472 LinkedHashMap<ObjectClass,String> ocMap = new LinkedHashMap<>(2); 473 ocMap.put(DirectoryServer.getTopObjectClass(), OC_TOP); 474 475 ObjectClass objectClass = 476 DirectoryServer.getObjectClass(OC_CRYPTO_INSTANCE_KEY, true); 477 ocMap.put(objectClass, OC_CRYPTO_INSTANCE_KEY); 478 479 LinkedHashMap<AttributeType,List<Attribute>> opAttrs = new LinkedHashMap<>(0); 480 LinkedHashMap<AttributeType,List<Attribute>> userAttrs = new LinkedHashMap<>(3); 481 482 userAttrs.put(t, Attributes.createAsList(t, v)); 483 484 485 t = DirectoryServer.getAttributeType(ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE); 486 AttributeBuilder builder = new AttributeBuilder(t); 487 builder.setOption("binary"); 488 builder.add(certValue); 489 userAttrs.put(t, builder.toAttributeList()); 490 491 492 Entry e = new Entry(entryDN, ocMap, userAttrs, opAttrs); 493 e.processVirtualAttributes(); 494 return e; 495 } 496 497 /** {@inheritDoc} */ 498 @Override 499 public void addEntry(Entry entry, AddOperation addOperation) 500 throws DirectoryException 501 { 502 DN entryDN = entry.getName(); 503 504 if (entryDN.equals(baseDN)) 505 { 506 LocalizableMessage message = ERR_TRUSTSTORE_INVALID_BASE.get(entryDN); 507 throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, message); 508 } 509 510 DN parentDN = DirectoryServer.getParentDNInSuffix(entryDN); 511 if (parentDN == null) 512 { 513 LocalizableMessage message = ERR_TRUSTSTORE_INVALID_BASE.get(entryDN); 514 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); 515 } 516 517 if (parentDN.equals(baseDN)) 518 { 519 addCertificate(entry); 520 } 521 else 522 { 523 LocalizableMessage message = ERR_TRUSTSTORE_INVALID_BASE.get(entryDN); 524 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); 525 } 526 } 527 528 /** {@inheritDoc} */ 529 @Override 530 public void deleteEntry(DN entryDN, DeleteOperation deleteOperation) 531 throws DirectoryException 532 { 533 if (entryDN.equals(baseDN)) 534 { 535 LocalizableMessage message = ERR_TRUSTSTORE_INVALID_BASE.get(entryDN); 536 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); 537 } 538 539 DN parentDN = DirectoryServer.getParentDNInSuffix(entryDN); 540 if (parentDN == null || !parentDN.equals(baseDN)) 541 { 542 LocalizableMessage message = ERR_TRUSTSTORE_INVALID_BASE.get(entryDN); 543 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); 544 } 545 546 deleteCertificate(entryDN); 547 } 548 549 /** {@inheritDoc} */ 550 @Override 551 public void replaceEntry(Entry oldEntry, Entry newEntry, 552 ModifyOperation modifyOperation) throws DirectoryException 553 { 554 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 555 ERR_BACKEND_MODIFY_NOT_SUPPORTED.get(oldEntry.getName(), getBackendID())); 556 } 557 558 /** {@inheritDoc} */ 559 @Override 560 public void renameEntry(DN currentDN, Entry entry, 561 ModifyDNOperation modifyDNOperation) 562 throws DirectoryException 563 { 564 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 565 ERR_BACKEND_MODIFY_DN_NOT_SUPPORTED.get(currentDN, getBackendID())); 566 } 567 568 /** {@inheritDoc} */ 569 @Override 570 public void search(SearchOperation searchOperation) 571 throws DirectoryException 572 { 573 // Get the base entry for the search, if possible. If it doesn't exist, 574 // then this will throw an exception. 575 DN baseDN = searchOperation.getBaseDN(); 576 Entry baseEntry = getEntry(baseDN); 577 578 579 // Look at the base DN and see if it's the trust store base DN, or a 580 // trust store entry DN. 581 SearchScope scope = searchOperation.getScope(); 582 SearchFilter filter = searchOperation.getFilter(); 583 if (this.baseDN.equals(baseDN)) 584 { 585 if ((scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) 586 && filter.matchesEntry(baseEntry)) 587 { 588 searchOperation.returnEntry(baseEntry, null); 589 } 590 591 String[] aliases = null; 592 try 593 { 594 aliases = certificateManager.getCertificateAliases(); 595 } 596 catch (KeyStoreException e) 597 { 598 logger.traceException(e); 599 } 600 601 if (aliases == null) 602 { 603 aliases = new String[0]; 604 } 605 606 if (scope != SearchScope.BASE_OBJECT && aliases.length != 0) 607 { 608 AttributeType certAliasType = DirectoryServer.getAttributeType(ATTR_CRYPTO_KEY_ID); 609 for (String alias : aliases) 610 { 611 DN certDN = makeChildDN(this.baseDN, certAliasType, alias); 612 613 Entry certEntry; 614 try 615 { 616 certEntry = getCertEntry(certDN); 617 } 618 catch (Exception e) 619 { 620 logger.traceException(e); 621 continue; 622 } 623 624 if (filter.matchesEntry(certEntry)) 625 { 626 searchOperation.returnEntry(certEntry, null); 627 } 628 } 629 } 630 } 631 else if (this.baseDN.equals(DirectoryServer.getParentDNInSuffix(baseDN))) 632 { 633 Entry certEntry = getCertEntry(baseDN); 634 635 if ((scope == SearchScope.BASE_OBJECT || scope == SearchScope.WHOLE_SUBTREE) 636 && filter.matchesEntry(certEntry)) 637 { 638 searchOperation.returnEntry(certEntry, null); 639 } 640 } 641 else 642 { 643 LocalizableMessage message = ERR_TRUSTSTORE_INVALID_BASE.get(baseDN); 644 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); 645 } 646 } 647 648 /** {@inheritDoc} */ 649 @Override 650 public Set<String> getSupportedControls() 651 { 652 return Collections.emptySet(); 653 } 654 655 /** {@inheritDoc} */ 656 @Override 657 public Set<String> getSupportedFeatures() 658 { 659 return Collections.emptySet(); 660 } 661 662 /** {@inheritDoc} */ 663 @Override 664 public boolean supports(BackendOperation backendOperation) 665 { 666 return false; 667 } 668 669 /** {@inheritDoc} */ 670 @Override 671 public void exportLDIF(LDIFExportConfig exportConfig) 672 throws DirectoryException 673 { 674 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 675 ERR_BACKEND_IMPORT_AND_EXPORT_NOT_SUPPORTED.get(getBackendID())); 676 } 677 678 /** {@inheritDoc} */ 679 @Override 680 public LDIFImportResult importLDIF(LDIFImportConfig importConfig, ServerContext serverContext) 681 throws DirectoryException 682 { 683 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 684 ERR_BACKEND_IMPORT_AND_EXPORT_NOT_SUPPORTED.get(getBackendID())); 685 } 686 687 /** {@inheritDoc} */ 688 @Override 689 public void createBackup(BackupConfig backupConfig) 690 throws DirectoryException 691 { 692 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 693 ERR_BACKEND_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(getBackendID())); 694 } 695 696 /** {@inheritDoc} */ 697 @Override 698 public void removeBackup(BackupDirectory backupDirectory, 699 String backupID) 700 throws DirectoryException 701 { 702 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 703 ERR_BACKEND_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(getBackendID())); 704 } 705 706 /** {@inheritDoc} */ 707 @Override 708 public void restoreBackup(RestoreConfig restoreConfig) 709 throws DirectoryException 710 { 711 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 712 ERR_BACKEND_BACKUP_AND_RESTORE_NOT_SUPPORTED.get(getBackendID())); 713 } 714 715 /** {@inheritDoc} */ 716 @Override 717 public ConditionResult hasSubordinates(DN entryDN) 718 throws DirectoryException 719 { 720 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, 721 ERR_HAS_SUBORDINATES_NOT_SUPPORTED.get()); 722 } 723 724 /** {@inheritDoc} */ 725 @Override 726 public long getNumberOfEntriesInBaseDN(DN baseDN) throws DirectoryException 727 { 728 checkNotNull(baseDN, "baseDN must not be null"); 729 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, ERR_NUM_SUBORDINATES_NOT_SUPPORTED.get()); 730 } 731 732 /** {@inheritDoc} */ 733 @Override 734 public long getNumberOfChildren(DN parentDN) throws DirectoryException 735 { 736 checkNotNull(parentDN, "parentDN must not be null"); 737 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, ERR_NUM_SUBORDINATES_NOT_SUPPORTED.get()); 738 } 739 740 /** {@inheritDoc} */ 741 @Override 742 public boolean isConfigurationChangeAcceptable( 743 TrustStoreBackendCfg configuration, List<LocalizableMessage> unacceptableReasons) 744 { 745 boolean configAcceptable = true; 746 DN cfgEntryDN = configuration.dn(); 747 748 749 // Get the path to the trust store file. 750 String newTrustStoreFile = configuration.getTrustStoreFile(); 751 try 752 { 753 File f = getFileForPath(newTrustStoreFile); 754 if (!f.exists() || !f.isFile()) 755 { 756 unacceptableReasons.add(ERR_TRUSTSTORE_NO_SUCH_FILE.get(newTrustStoreFile, cfgEntryDN)); 757 configAcceptable = false; 758 } 759 } 760 catch (Exception e) 761 { 762 logger.traceException(e); 763 764 unacceptableReasons.add(ERR_TRUSTSTORE_CANNOT_DETERMINE_FILE.get(cfgEntryDN, getExceptionMessage(e))); 765 configAcceptable = false; 766 } 767 768 769 // Check to see if the trust store type is acceptable. 770 String storeType = configuration.getTrustStoreType(); 771 if (storeType != null) 772 { 773 try 774 { 775 KeyStore.getInstance(storeType); 776 } 777 catch (KeyStoreException kse) 778 { 779 logger.traceException(kse); 780 781 unacceptableReasons.add(ERR_TRUSTSTORE_INVALID_TYPE.get( 782 storeType, cfgEntryDN, getExceptionMessage(kse))); 783 configAcceptable = false; 784 } 785 } 786 787 788 // If there is a PIN property, then make sure the corresponding 789 // property is set. 790 String pinProp = configuration.getTrustStorePinProperty(); 791 if (pinProp != null && System.getProperty(pinProp) == null) 792 { 793 unacceptableReasons.add(ERR_TRUSTSTORE_PIN_PROPERTY_NOT_SET.get(pinProp, cfgEntryDN)); 794 configAcceptable = false; 795 } 796 797 798 // If there is a PIN environment variable, then make sure the corresponding 799 // environment variable is set. 800 String pinEnVar = configuration.getTrustStorePinEnvironmentVariable(); 801 if (pinEnVar != null && System.getenv(pinEnVar) == null) 802 { 803 unacceptableReasons.add(ERR_TRUSTSTORE_PIN_ENVAR_NOT_SET.get(pinEnVar, cfgEntryDN)); 804 configAcceptable = false; 805 } 806 807 808 // If there is a PIN file, then make sure the file is readable if it exists. 809 String pinFile = configuration.getTrustStorePinFile(); 810 if (pinFile != null) 811 { 812 File f = new File(pinFile); 813 if (f.exists()) 814 { 815 String pinStr = null; 816 817 BufferedReader br = null; 818 try 819 { 820 br = new BufferedReader(new FileReader(pinFile)); 821 pinStr = br.readLine(); 822 } 823 catch (IOException ioe) 824 { 825 unacceptableReasons.add(ERR_TRUSTSTORE_PIN_FILE_CANNOT_READ.get( 826 pinFile, cfgEntryDN, getExceptionMessage(ioe))); 827 configAcceptable = false; 828 } 829 finally 830 { 831 close(br); 832 } 833 834 if (pinStr == null) 835 { 836 unacceptableReasons.add(ERR_TRUSTSTORE_PIN_FILE_EMPTY.get(pinFile, cfgEntryDN)); 837 configAcceptable = false; 838 } 839 } 840 } 841 842 843 return configAcceptable; 844 } 845 846 /** {@inheritDoc} */ 847 @Override 848 public ConfigChangeResult applyConfigurationChange(TrustStoreBackendCfg cfg) 849 { 850 final ConfigChangeResult ccr = new ConfigChangeResult(); 851 DN configEntryDN = cfg.dn(); 852 853 // Get the path to the trust store file. 854 String newTrustStoreFile = cfg.getTrustStoreFile(); 855 File f = getFileForPath(newTrustStoreFile); 856 if (!f.exists() || !f.isFile()) 857 { 858 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 859 ccr.addMessage(ERR_TRUSTSTORE_NO_SUCH_FILE.get(newTrustStoreFile, configEntryDN)); 860 } 861 862 863 // Get the trust store type. If none is specified, then use the default 864 // type. 865 String newTrustStoreType = cfg.getTrustStoreType(); 866 if (newTrustStoreType == null) 867 { 868 newTrustStoreType = KeyStore.getDefaultType(); 869 } 870 871 try 872 { 873 KeyStore.getInstance(newTrustStoreType); 874 } 875 catch (KeyStoreException kse) 876 { 877 logger.traceException(kse); 878 879 ccr.addMessage(ERR_TRUSTSTORE_INVALID_TYPE.get(newTrustStoreType, configEntryDN, getExceptionMessage(kse))); 880 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 881 } 882 883 884 // Get the PIN needed to access the contents of the trust store file. We 885 // will offer several places to look for the PIN, and we will do so in the 886 // following order: 887 // - In a specified Java property 888 // - In a specified environment variable 889 // - In a specified file on the server filesystem. 890 // - As the value of a configuration attribute. 891 // In any case, the PIN must be in the clear. If no PIN is provided, then 892 // it will be assumed that none is required to access the information in the 893 // trust store. 894 char[] newPIN = null; 895 String newPINProperty = cfg.getTrustStorePinProperty(); 896 if (newPINProperty == null) 897 { 898 String newPINEnVar = cfg.getTrustStorePinEnvironmentVariable(); 899 if (newPINEnVar == null) 900 { 901 String newPINFile = cfg.getTrustStorePinFile(); 902 if (newPINFile == null) 903 { 904 String pinStr = cfg.getTrustStorePin(); 905 if (pinStr == null) 906 { 907 newPIN = null; 908 } 909 else 910 { 911 newPIN = pinStr.toCharArray(); 912 } 913 } 914 else 915 { 916 File pinFile = getFileForPath(newPINFile); 917 if (! pinFile.exists()) 918 { 919 try 920 { 921 // Generate a PIN. 922 newPIN = createKeystorePassword(); 923 924 // Store the PIN in the pin file. 925 createPINFile(pinFile.getPath(), new String(newPIN)); 926 } 927 catch (Exception e) 928 { 929 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 930 ccr.addMessage(ERR_TRUSTSTORE_PIN_FILE_CANNOT_CREATE.get(newPINFile, configEntryDN)); 931 } 932 } 933 else 934 { 935 String pinStr = null; 936 937 BufferedReader br = null; 938 try 939 { 940 br = new BufferedReader(new FileReader(pinFile)); 941 pinStr = br.readLine(); 942 } 943 catch (IOException ioe) 944 { 945 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 946 ccr.addMessage(ERR_TRUSTSTORE_PIN_FILE_CANNOT_READ.get( 947 newPINFile, configEntryDN, getExceptionMessage(ioe))); 948 } 949 finally 950 { 951 close(br); 952 } 953 954 if (pinStr == null) 955 { 956 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 957 ccr.addMessage(ERR_TRUSTSTORE_PIN_FILE_EMPTY.get(newPINFile, configEntryDN)); 958 } 959 else 960 { 961 newPIN = pinStr.toCharArray(); 962 } 963 } 964 } 965 } 966 else 967 { 968 String pinStr = System.getenv(newPINEnVar); 969 if (pinStr == null) 970 { 971 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 972 ccr.addMessage(ERR_TRUSTSTORE_PIN_ENVAR_NOT_SET.get(newPINEnVar, configEntryDN)); 973 } 974 else 975 { 976 newPIN = pinStr.toCharArray(); 977 } 978 } 979 } 980 else 981 { 982 String pinStr = System.getProperty(newPINProperty); 983 if (pinStr == null) 984 { 985 ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); 986 ccr.addMessage(ERR_TRUSTSTORE_PIN_PROPERTY_NOT_SET.get(newPINProperty, configEntryDN)); 987 } 988 else 989 { 990 newPIN = pinStr.toCharArray(); 991 } 992 } 993 994 995 if (ccr.getResultCode() == ResultCode.SUCCESS) 996 { 997 trustStoreFile = newTrustStoreFile; 998 trustStoreType = newTrustStoreType; 999 trustStorePIN = newPIN; 1000 configuration = cfg; 1001 certificateManager = 1002 new CertificateManager(getFileForPath(trustStoreFile).getPath(), 1003 trustStoreType, 1004 new String(trustStorePIN)); 1005 } 1006 1007 return ccr; 1008 } 1009 1010 /** 1011 * Create a new child DN from a given parent DN. The child RDN is formed 1012 * from a given attribute type and string value. 1013 * @param parentDN The DN of the parent. 1014 * @param rdnAttrType The attribute type of the RDN. 1015 * @param rdnStringValue The string value of the RDN. 1016 * @return A new child DN. 1017 */ 1018 public static DN makeChildDN(DN parentDN, AttributeType rdnAttrType, 1019 String rdnStringValue) 1020 { 1021 ByteString attrValue = ByteString.valueOfUtf8(rdnStringValue); 1022 return parentDN.child(new RDN(rdnAttrType, attrValue)); 1023 } 1024 1025 1026 /** 1027 * Retrieves a set of <CODE>KeyManager</CODE> objects that may be used for 1028 * interactions requiring access to a key manager. 1029 * 1030 * @return A set of <CODE>KeyManager</CODE> objects that may be used for 1031 * interactions requiring access to a key manager. 1032 * 1033 * @throws DirectoryException If a problem occurs while attempting to obtain 1034 * the set of key managers. 1035 */ 1036 public KeyManager[] getKeyManagers() 1037 throws DirectoryException 1038 { 1039 final KeyStore keyStore; 1040 try (final FileInputStream inputStream = new FileInputStream(getFileForPath(trustStoreFile))) 1041 { 1042 keyStore = KeyStore.getInstance(trustStoreType); 1043 keyStore.load(inputStream, trustStorePIN); 1044 } 1045 catch (Exception e) 1046 { 1047 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_LOAD.get( 1048 trustStoreFile, getExceptionMessage(e)); 1049 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1050 message, e); 1051 } 1052 1053 try 1054 { 1055 String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm(); 1056 KeyManagerFactory keyManagerFactory = 1057 KeyManagerFactory.getInstance(keyManagerAlgorithm); 1058 keyManagerFactory.init(keyStore, trustStorePIN); 1059 return keyManagerFactory.getKeyManagers(); 1060 } 1061 catch (Exception e) 1062 { 1063 logger.traceException(e); 1064 1065 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_CREATE_FACTORY.get( 1066 trustStoreFile, getExceptionMessage(e)); 1067 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1068 message, e); 1069 } 1070 } 1071 1072 1073 /** 1074 * Retrieves a set of {@code TrustManager} objects that may be used 1075 * for interactions requiring access to a trust manager. 1076 * 1077 * @return A set of {@code TrustManager} objects that may be used 1078 * for interactions requiring access to a trust manager. 1079 * 1080 * @throws DirectoryException If a problem occurs while attempting 1081 * to obtain the set of trust managers. 1082 */ 1083 public TrustManager[] getTrustManagers() 1084 throws DirectoryException 1085 { 1086 KeyStore trustStore; 1087 FileInputStream inputStream = null; 1088 try 1089 { 1090 trustStore = KeyStore.getInstance(trustStoreType); 1091 1092 inputStream = 1093 new FileInputStream(getFileForPath(trustStoreFile)); 1094 trustStore.load(inputStream, trustStorePIN); 1095 } 1096 catch (Exception e) 1097 { 1098 logger.traceException(e); 1099 1100 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_LOAD.get( 1101 trustStoreFile, getExceptionMessage(e)); 1102 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1103 message, e); 1104 } 1105 finally 1106 { 1107 close(inputStream); 1108 } 1109 1110 1111 try 1112 { 1113 String trustManagerAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); 1114 TrustManagerFactory trustManagerFactory = 1115 TrustManagerFactory.getInstance(trustManagerAlgorithm); 1116 trustManagerFactory.init(trustStore); 1117 return trustManagerFactory.getTrustManagers(); 1118 } 1119 catch (Exception e) 1120 { 1121 logger.traceException(e); 1122 1123 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_CREATE_FACTORY.get( 1124 trustStoreFile, getExceptionMessage(e)); 1125 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1126 message, e); 1127 } 1128 } 1129 1130 1131 /** 1132 * Returns the key associated with the given alias, using the trust 1133 * store pin to recover it. 1134 * 1135 * @param alias The alias name. 1136 * 1137 * @return The requested key, or null if the given alias does not exist 1138 * or does not identify a key-related entry. 1139 * 1140 * @throws DirectoryException If an error occurs while retrieving the key. 1141 */ 1142 public Key getKey(String alias) 1143 throws DirectoryException 1144 { 1145 KeyStore trustStore; 1146 FileInputStream inputStream = null; 1147 try 1148 { 1149 trustStore = KeyStore.getInstance(trustStoreType); 1150 1151 inputStream = 1152 new FileInputStream(getFileForPath(trustStoreFile)); 1153 trustStore.load(inputStream, trustStorePIN); 1154 } 1155 catch (Exception e) 1156 { 1157 logger.traceException(e); 1158 1159 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_LOAD.get( 1160 trustStoreFile, getExceptionMessage(e)); 1161 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1162 message, e); 1163 } 1164 finally 1165 { 1166 close(inputStream); 1167 } 1168 1169 try 1170 { 1171 return trustStore.getKey(alias, trustStorePIN); 1172 } 1173 catch (Exception e) 1174 { 1175 logger.traceException(e); 1176 1177 LocalizableMessage message = ERR_TRUSTSTORE_ERROR_READING_KEY.get( 1178 alias, trustStoreFile, getExceptionMessage(e)); 1179 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 1180 message, e); 1181 } 1182 } 1183 1184 1185 private void addCertificate(Entry entry) 1186 throws DirectoryException 1187 { 1188 DN entryDN = entry.getName(); 1189 1190 // Make sure that the DN specifies a certificate alias. 1191 AttributeType t = DirectoryServer.getAttributeType(ATTR_CRYPTO_KEY_ID); 1192 ByteString v = entryDN.rdn().getAttributeValue(t); 1193 if (v == null) 1194 { 1195 LocalizableMessage message = ERR_TRUSTSTORE_DN_DOES_NOT_SPECIFY_CERTIFICATE.get(entryDN); 1196 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, baseDN, null); 1197 } 1198 1199 String certAlias = v.toString(); 1200 try 1201 { 1202 if (certificateManager.aliasInUse(certAlias)) 1203 { 1204 LocalizableMessage message = ERR_TRUSTSTORE_ALIAS_IN_USE.get(entryDN); 1205 throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, message); 1206 } 1207 1208 ObjectClass ocSelfSignedCertRequest = 1209 DirectoryServer.getObjectClass(OC_SELF_SIGNED_CERT_REQUEST, true); 1210 if (entry.hasObjectClass(ocSelfSignedCertRequest)) 1211 { 1212 try 1213 { 1214 final KeyType keyType = KeyType.getTypeOrDefault(certAlias); 1215 certificateManager.generateSelfSignedCertificate( 1216 keyType, 1217 certAlias, 1218 getADSCertificateSubjectDN(keyType), 1219 getADSCertificateValidity()); 1220 } 1221 catch (Exception e) 1222 { 1223 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_GENERATE_CERT.get( 1224 certAlias, trustStoreFile, getExceptionMessage(e)); 1225 throw new DirectoryException( 1226 DirectoryServer.getServerErrorResultCode(), message, e); 1227 } 1228 } 1229 else 1230 { 1231 List<Attribute> certAttrs = entry.getAttribute( 1232 ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE); 1233 if (certAttrs.isEmpty()) 1234 { 1235 LocalizableMessage message = 1236 ERR_TRUSTSTORE_ENTRY_MISSING_CERT_ATTR.get(entryDN, ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE); 1237 throw new DirectoryException( 1238 DirectoryServer.getServerErrorResultCode(), message); 1239 } 1240 if (certAttrs.size() != 1) 1241 { 1242 LocalizableMessage message = 1243 ERR_TRUSTSTORE_ENTRY_HAS_MULTIPLE_CERT_ATTRS.get(entryDN, ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE); 1244 throw new DirectoryException( 1245 DirectoryServer.getServerErrorResultCode(), message); 1246 } 1247 1248 Attribute certAttr = certAttrs.get(0); 1249 Iterator<ByteString> i = certAttr.iterator(); 1250 1251 if (!i.hasNext()) 1252 { 1253 LocalizableMessage message = 1254 ERR_TRUSTSTORE_ENTRY_MISSING_CERT_VALUE.get(entryDN, ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE); 1255 throw new DirectoryException( 1256 DirectoryServer.getServerErrorResultCode(), message); 1257 } 1258 1259 ByteString certBytes = i.next(); 1260 1261 if (i.hasNext()) 1262 { 1263 LocalizableMessage message = 1264 ERR_TRUSTSTORE_ENTRY_HAS_MULTIPLE_CERT_VALUES.get(entryDN, ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE); 1265 throw new DirectoryException( 1266 DirectoryServer.getServerErrorResultCode(), message); 1267 } 1268 1269 try 1270 { 1271 File tempDir = getFileForPath("config"); 1272 File tempFile = File.createTempFile(configuration.getBackendId(), 1273 certAlias, tempDir); 1274 try 1275 { 1276 FileOutputStream outputStream = 1277 new FileOutputStream(tempFile.getPath(), false); 1278 try 1279 { 1280 certBytes.copyTo(outputStream); 1281 } 1282 finally 1283 { 1284 outputStream.close(); 1285 } 1286 1287 certificateManager.addCertificate(certAlias, tempFile); 1288 } 1289 finally 1290 { 1291 tempFile.delete(); 1292 } 1293 } 1294 catch (IOException e) 1295 { 1296 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_WRITE_CERT.get( 1297 certAlias, getExceptionMessage(e)); 1298 throw new DirectoryException( 1299 DirectoryServer.getServerErrorResultCode(), message, e); 1300 } 1301 } 1302 } 1303 catch (Exception e) 1304 { 1305 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_ADD_CERT.get( 1306 certAlias, trustStoreFile, getExceptionMessage(e)); 1307 throw new DirectoryException( 1308 DirectoryServer.getServerErrorResultCode(), message, e); 1309 } 1310 1311 } 1312 1313 1314 private void deleteCertificate(DN entryDN) 1315 throws DirectoryException 1316 { 1317 // Make sure that the DN specifies a certificate alias. 1318 AttributeType t = DirectoryServer.getAttributeType(ATTR_CRYPTO_KEY_ID); 1319 ByteString v = entryDN.rdn().getAttributeValue(t); 1320 if (v == null) 1321 { 1322 LocalizableMessage message = ERR_TRUSTSTORE_DN_DOES_NOT_SPECIFY_CERTIFICATE.get(entryDN); 1323 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, baseDN, null); 1324 } 1325 1326 String certAlias = v.toString(); 1327 try 1328 { 1329 if (!certificateManager.aliasInUse(certAlias)) 1330 { 1331 LocalizableMessage message = ERR_TRUSTSTORE_INVALID_BASE.get(entryDN); 1332 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); 1333 } 1334 1335 certificateManager.removeCertificate(certAlias); 1336 } 1337 catch (Exception e) 1338 { 1339 LocalizableMessage message = ERR_TRUSTSTORE_CANNOT_DELETE_CERT.get( 1340 certAlias, trustStoreFile, getExceptionMessage(e)); 1341 throw new DirectoryException( 1342 DirectoryServer.getServerErrorResultCode(), message, e); 1343 } 1344 } 1345 1346 1347 /** 1348 * Returns the validity period to be used to generate the ADS certificate. 1349 * @return The validity period to be used to generate the ADS certificate. 1350 */ 1351 private static int getADSCertificateValidity() 1352 { 1353 return 20 * 365; 1354 } 1355 1356 /** 1357 * Returns the Subject DN to be used to generate the ADS certificate. 1358 * @return The Subject DN to be used to generate the ADS certificate. 1359 * @throws java.net.UnknownHostException If the server host name could not be 1360 * determined. 1361 */ 1362 private static String getADSCertificateSubjectDN(KeyType keyType) throws UnknownHostException 1363 { 1364 final String hostName = SetupUtils.getHostNameForCertificate(DirectoryServer.getServerRoot()); 1365 return "cn=" + Rdn.escapeValue(hostName) + ",O=OpenDJ " + keyType + " Certificate"; 1366 } 1367 1368 /** 1369 * Create a randomly generated password for a certificate keystore. 1370 * @return A randomly generated password for a certificate keystore. 1371 */ 1372 private static char[] createKeystorePassword() { 1373 int pwdLength = 50; 1374 char[] pwd = new char[pwdLength]; 1375 Random random = new Random(); 1376 for (int pos=0; pos < pwdLength; pos++) { 1377 int type = getRandomInt(random,3); 1378 char nextChar = getRandomChar(random,type); 1379 pwd[pos] = nextChar; 1380 } 1381 return pwd; 1382 } 1383 1384 private static char getRandomChar(Random random, int type) 1385 { 1386 char generatedChar; 1387 int next = random.nextInt(); 1388 int d; 1389 1390 switch (type) 1391 { 1392 case 0: 1393 // Will return a digit 1394 d = next % 10; 1395 if (d < 0) 1396 { 1397 d = d * -1; 1398 } 1399 generatedChar = (char) (d+48); 1400 break; 1401 case 1: 1402 // Will return a lower case letter 1403 d = next % 26; 1404 if (d < 0) 1405 { 1406 d = d * -1; 1407 } 1408 generatedChar = (char) (d + 97); 1409 break; 1410 default: 1411 // Will return a capital letter 1412 d = next % 26; 1413 if (d < 0) 1414 { 1415 d = d * -1; 1416 } 1417 generatedChar = (char) (d + 65) ; 1418 } 1419 1420 return generatedChar; 1421 } 1422 1423 private static int getRandomInt(Random random,int modulo) 1424 { 1425 return random.nextInt() & modulo; 1426 } 1427 1428 /** 1429 * Creates a PIN file on the specified path. 1430 * @param path the path where the PIN file will be created. 1431 * @param pin The PIN to store in the file. 1432 * @throws IOException if something goes wrong. 1433 */ 1434 public static void createPINFile(String path, String pin) 1435 throws IOException 1436 { 1437 try (final FileWriter file = new FileWriter(path); 1438 final PrintWriter out = new PrintWriter(file)) 1439 { 1440 out.println(pin); 1441 out.flush(); 1442 } 1443 1444 try { 1445 if (!FilePermission.setPermissions(new File(path), 1446 new FilePermission(0600))) 1447 { 1448 // Log a warning that the permissions were not set. 1449 logger.warn(WARN_TRUSTSTORE_SET_PERMISSIONS_FAILED, path); 1450 } 1451 } catch(DirectoryException e) { 1452 // Log a warning that the permissions were not set. 1453 logger.warn(WARN_TRUSTSTORE_SET_PERMISSIONS_FAILED, path); 1454 } 1455 } 1456 1457 /** 1458 * Generates a self-signed certificate with well-known alias if there is none. 1459 * @throws InitializationException If an error occurs while interacting with 1460 * the key store. 1461 */ 1462 private void generateInstanceCertificateIfAbsent() throws InitializationException 1463 { 1464 final String certAlias = ADS_CERTIFICATE_ALIAS; 1465 try 1466 { 1467 if (certificateManager.aliasInUse(certAlias)) 1468 { 1469 return; 1470 } 1471 } 1472 catch (Exception e) 1473 { 1474 LocalizableMessage message = 1475 ERR_TRUSTSTORE_CANNOT_ADD_CERT.get(certAlias, trustStoreFile, getExceptionMessage(e)); 1476 throw new InitializationException(message, e); 1477 } 1478 1479 try 1480 { 1481 final KeyType keyType = KeyType.getTypeOrDefault(certAlias); 1482 certificateManager.generateSelfSignedCertificate(keyType, certAlias, getADSCertificateSubjectDN(keyType), 1483 getADSCertificateValidity()); 1484 } 1485 catch (Exception e) 1486 { 1487 LocalizableMessage message = 1488 ERR_TRUSTSTORE_CANNOT_GENERATE_CERT.get(certAlias, trustStoreFile, getExceptionMessage(e)); 1489 throw new InitializationException(message, e); 1490 } 1491 } 1492} 1493