001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.server.core.security; 021 022 023 import java.io.IOException; 024 import java.io.InputStream; 025 import java.io.OutputStream; 026 import java.security.Key; 027 import java.security.KeyPair; 028 import java.security.KeyStoreException; 029 import java.security.KeyStoreSpi; 030 import java.security.NoSuchAlgorithmException; 031 import java.security.UnrecoverableKeyException; 032 import java.security.cert.Certificate; 033 import java.security.cert.CertificateException; 034 import java.security.cert.X509Certificate; 035 import java.util.Date; 036 import java.util.Enumeration; 037 038 import org.apache.commons.lang.ArrayUtils; 039 import org.apache.commons.lang.NotImplementedException; 040 import org.apache.directory.server.constants.ServerDNConstants; 041 import org.apache.directory.server.core.CoreSession; 042 import org.apache.directory.server.core.DirectoryService; 043 import org.apache.directory.server.core.LdapPrincipal; 044 import org.apache.directory.server.i18n.I18n; 045 import org.apache.directory.shared.ldap.constants.AuthenticationLevel; 046 import org.apache.directory.shared.ldap.entry.ServerEntry; 047 import org.apache.directory.shared.ldap.name.DN; 048 import org.apache.directory.shared.ldap.util.SingletonEnumeration; 049 import org.slf4j.Logger; 050 import org.slf4j.LoggerFactory; 051 052 053 /** 054 * A read only key store facility designed specifically for TLS/CA operations. 055 * It is only intended for accessing the 'apacheds' private/public key pairs 056 * as well as the self signed certificate. 057 * 058 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 059 * @version $Rev$, $Date$ 060 */ 061 public class CoreKeyStoreSpi extends KeyStoreSpi 062 { 063 private static final String APACHEDS_ALIAS = "apacheds"; 064 065 private static final Logger LOG = LoggerFactory.getLogger( CoreKeyStoreSpi.class ); 066 067 private DirectoryService directoryService; 068 069 070 /** 071 * Creates a new instance of LocalKeyStore. 072 */ 073 public CoreKeyStoreSpi( DirectoryService directoryService ) 074 { 075 LOG.debug( "Constructor called." ); 076 this.directoryService = directoryService; 077 } 078 079 080 private ServerEntry getTlsEntry() throws Exception 081 { 082 DN adminDn = new DN( ServerDNConstants.ADMIN_SYSTEM_DN ); 083 adminDn.normalize( directoryService.getSchemaManager().getNormalizerMapping() ); 084 LdapPrincipal principal = new LdapPrincipal( adminDn, AuthenticationLevel.SIMPLE ); 085 CoreSession session = directoryService.getSession( principal ); 086 return session.lookup( adminDn ); 087 } 088 089 090 /* (non-Javadoc) 091 * @see java.security.KeyStoreSpi#engineAliases() 092 */ 093 @Override 094 public Enumeration<String> engineAliases() 095 { 096 LOG.debug( "engineAliases() called." ); 097 return new SingletonEnumeration<String>( APACHEDS_ALIAS ); 098 } 099 100 101 /* (non-Javadoc) 102 * @see java.security.KeyStoreSpi#engineContainsAlias(java.lang.String) 103 */ 104 @Override 105 public boolean engineContainsAlias( String alias ) 106 { 107 LOG.debug( "engineContainsAlias({}) called.", alias ); 108 109 if ( alias.equalsIgnoreCase( APACHEDS_ALIAS ) ) 110 { 111 return true; 112 } 113 114 return false; 115 } 116 117 118 /* (non-Javadoc) 119 * @see java.security.KeyStoreSpi#engineDeleteEntry(java.lang.String) 120 */ 121 @Override 122 public void engineDeleteEntry( String alias ) throws KeyStoreException 123 { 124 LOG.debug( "engineDeleteEntry({}) called.", alias ); 125 throw new UnsupportedOperationException(); 126 } 127 128 129 /* (non-Javadoc) 130 * @see java.security.KeyStoreSpi#engineGetCertificate(java.lang.String) 131 */ 132 @Override 133 public Certificate engineGetCertificate( String alias ) 134 { 135 LOG.debug( "engineGetCertificate({}) called.", alias ); 136 if ( alias.equalsIgnoreCase( APACHEDS_ALIAS ) ) 137 { 138 try 139 { 140 ServerEntry entry = getTlsEntry(); 141 return TlsKeyGenerator.getCertificate( entry ); 142 } 143 catch ( Exception e ) 144 { 145 LOG.error( I18n.err( I18n.ERR_65 ), e ); 146 } 147 } 148 149 return null; 150 } 151 152 153 /* (non-Javadoc) 154 * @see java.security.KeyStoreSpi#engineGetCertificateAlias(java.security.cert.Certificate) 155 */ 156 @Override 157 public String engineGetCertificateAlias( Certificate cert ) 158 { 159 LOG.debug( "engineGetCertificateAlias({}) called.", cert ); 160 161 if ( cert instanceof X509Certificate ) 162 { 163 LOG.debug( "Certificate in alias request is X.509 based." ); 164 X509Certificate xcert = ( X509Certificate ) cert; 165 if ( xcert.getSubjectDN().toString().equals( TlsKeyGenerator.CERTIFICATE_PRINCIPAL_DN ) ) 166 { 167 return APACHEDS_ALIAS; 168 } 169 } 170 171 try 172 { 173 ServerEntry entry = getTlsEntry(); 174 if ( ArrayUtils.isEquals( cert.getEncoded(), entry.get( TlsKeyGenerator.USER_CERTIFICATE_AT ).getBytes() ) ) 175 { 176 return APACHEDS_ALIAS; 177 } 178 } 179 catch ( Exception e ) 180 { 181 LOG.error( I18n.err( I18n.ERR_66 ), e ); 182 } 183 184 return null; 185 } 186 187 188 /* (non-Javadoc) 189 * @see java.security.KeyStoreSpi#engineGetCertificateChain(java.lang.String) 190 */ 191 @Override 192 public Certificate[] engineGetCertificateChain( String alias ) 193 { 194 LOG.debug( "engineGetCertificateChain({}) called.", alias ); 195 try 196 { 197 ServerEntry entry = getTlsEntry(); 198 LOG.debug( "Entry:\n{}", entry ); 199 return new Certificate[] { TlsKeyGenerator.getCertificate( entry ) }; 200 } 201 catch ( Exception e ) 202 { 203 LOG.error( I18n.err( I18n.ERR_66 ), e ); 204 } 205 206 return new Certificate[0]; 207 } 208 209 210 /* (non-Javadoc) 211 * @see java.security.KeyStoreSpi#engineGetCreationDate(java.lang.String) 212 */ 213 @Override 214 public Date engineGetCreationDate( String alias ) 215 { 216 LOG.debug( "engineGetCreationDate({}) called.", alias ); 217 return new Date(); 218 } 219 220 221 /* (non-Javadoc) 222 * @see java.security.KeyStoreSpi#engineGetKey(java.lang.String, char[]) 223 */ 224 @Override 225 public Key engineGetKey( String alias, char[] password ) throws NoSuchAlgorithmException, UnrecoverableKeyException 226 { 227 LOG.debug( "engineGetKey({}, {}) called.", alias, password ); 228 229 try 230 { 231 ServerEntry entry = getTlsEntry(); 232 KeyPair keyPair = TlsKeyGenerator.getKeyPair( entry ); 233 return keyPair.getPrivate(); 234 } 235 catch ( Exception e ) 236 { 237 LOG.error( I18n.err( I18n.ERR_68 ), e ); 238 } 239 240 return null; 241 } 242 243 244 /* (non-Javadoc) 245 * @see java.security.KeyStoreSpi#engineIsCertificateEntry(java.lang.String) 246 */ 247 @Override 248 public boolean engineIsCertificateEntry( String alias ) 249 { 250 LOG.debug( "engineIsCertificateEntry({}) called.", alias ); 251 return false; 252 } 253 254 255 /* (non-Javadoc) 256 * @see java.security.KeyStoreSpi#engineIsKeyEntry(java.lang.String) 257 */ 258 @Override 259 public boolean engineIsKeyEntry( String alias ) 260 { 261 LOG.debug( "engineIsKeyEntry({}) called.", alias ); 262 return true; 263 } 264 265 266 /* (non-Javadoc) 267 * @see java.security.KeyStoreSpi#engineLoad(java.io.InputStream, char[]) 268 */ 269 @Override 270 public void engineLoad( InputStream stream, char[] password ) throws IOException, NoSuchAlgorithmException, 271 CertificateException 272 { 273 LOG.debug( "engineLoad({}, {}) called.", stream, password ); 274 } 275 276 277 /* (non-Javadoc) 278 * @see java.security.KeyStoreSpi#engineSetCertificateEntry(java.lang.String, java.security.cert.Certificate) 279 */ 280 @Override 281 public void engineSetCertificateEntry( String alias, Certificate cert ) throws KeyStoreException 282 { 283 LOG.debug( "engineSetCertificateEntry({}, {}) called.", alias, cert ); 284 throw new NotImplementedException(); 285 } 286 287 288 /* (non-Javadoc) 289 * @see java.security.KeyStoreSpi#engineSetKeyEntry(java.lang.String, byte[], java.security.cert.Certificate[]) 290 */ 291 @Override 292 public void engineSetKeyEntry( String alias, byte[] key, Certificate[] chain ) throws KeyStoreException 293 { 294 LOG.debug( "engineSetKeyEntry({}, key, {}) called.", alias, chain ); 295 throw new NotImplementedException(); 296 } 297 298 299 /* (non-Javadoc) 300 * @see java.security.KeyStoreSpi#engineSetKeyEntry(java.lang.String, java.security.Key, char[], java.security.cert.Certificate[]) 301 */ 302 @Override 303 public void engineSetKeyEntry( String alias, Key key, char[] password, Certificate[] chain ) 304 throws KeyStoreException 305 { 306 LOG.debug( "engineSetKeyEntry({}, key, {}, chain) called.", alias, new String( password ) ); 307 throw new NotImplementedException(); 308 } 309 310 311 /* (non-Javadoc) 312 * @see java.security.KeyStoreSpi#engineSize() 313 */ 314 @Override 315 public int engineSize() 316 { 317 LOG.debug( "engineSize() called." ); 318 return 1; 319 } 320 321 322 /* (non-Javadoc) 323 * @see java.security.KeyStoreSpi#engineStore(java.io.OutputStream, char[]) 324 */ 325 @Override 326 public void engineStore( OutputStream stream, char[] password ) throws IOException, NoSuchAlgorithmException, 327 CertificateException 328 { 329 LOG.debug( "engineStore(stream, {}) called.", new String( password ) ); 330 } 331 }