001    /*
002     * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003     * Copyright (C) 2011 NightLabs Consulting GmbH
004     *
005     * This program is free software: you can redistribute it and/or modify
006     * it under the terms of the GNU Affero General Public License as
007     * published by the Free Software Foundation, either version 3 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU Affero General Public License for more details.
014     *
015     * You should have received a copy of the GNU Affero General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    package org.cumulus4j.keymanager.channel;
019    
020    import java.io.IOException;
021    import java.security.GeneralSecurityException;
022    import java.util.Collections;
023    import java.util.Date;
024    import java.util.Map;
025    import java.util.WeakHashMap;
026    
027    import org.bouncycastle.crypto.CryptoException;
028    import org.cumulus4j.keymanager.Session;
029    import org.cumulus4j.keymanager.SessionManager;
030    import org.cumulus4j.keymanager.back.shared.GetActiveEncryptionKeyRequest;
031    import org.cumulus4j.keymanager.back.shared.GetActiveEncryptionKeyResponse;
032    import org.cumulus4j.keymanager.back.shared.GetKeyResponse;
033    import org.cumulus4j.keymanager.back.shared.KeyEncryptionUtil;
034    import org.cumulus4j.keymanager.back.shared.Response;
035    import org.cumulus4j.keystore.AuthenticationException;
036    import org.cumulus4j.keystore.DateDependentKeyStrategy;
037    import org.cumulus4j.keystore.KeyNotFoundException;
038    import org.cumulus4j.keystore.KeyStore;
039    
040    /**
041     * <p>
042     * Handler for {@link GetActiveEncryptionKeyRequest}.
043     * </p>
044     * <p>
045     * If the {@link Session} is found for the given
046     * {@link org.cumulus4j.keymanager.back.shared.Request#getCryptoSessionID() cryptoSessionID} and
047     * it is not {@link Session#isReleased() locked}, this handler determines the currently active
048     * encryption key and sends it in a {@link GetKeyResponse} to the server.
049     * </p>
050     *
051     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
052     */
053    public class GetActiveEncryptionKeyRequestHandler extends AbstractRequestHandler<GetActiveEncryptionKeyRequest>
054    {
055            private static Map<KeyStore, DateDependentKeyStrategy.ActiveKey> keyStore2activeKey = Collections.synchronizedMap(
056                            new WeakHashMap<KeyStore, DateDependentKeyStrategy.ActiveKey>()
057            );
058    
059            @Override
060            public Response handle(GetActiveEncryptionKeyRequest request)
061            throws AuthenticationException, KeyNotFoundException, IOException, GeneralSecurityException, CryptoException
062            {
063                    SessionManager sessionManager = getKeyManagerChannelManager().getSessionManager();
064                    Session session = sessionManager.getSessionForCryptoSessionID(request.getCryptoSessionID());
065    
066                    // TODO typed exceptions/typed responses?!
067                    if (session == null)
068                            throw new IllegalStateException("There is no session for cryptoSessionID=" + request.getCryptoSessionID() + "!");
069    
070                    if (session.isReleased())
071                            throw new IllegalStateException("The session for cryptoSessionID=" + request.getCryptoSessionID() + " is currently locked!");
072    
073                    if (session.getExpiry().before(new Date()))
074                            throw new IllegalStateException("The session for cryptoSessionID=" + request.getCryptoSessionID() + " is already expired!");
075    
076                    if (request.getTimestamp() == null)
077                            throw new IllegalArgumentException("request.getTimestamp() == null");
078    
079                    KeyStore keyStore = sessionManager.getKeyStore();
080                    DateDependentKeyStrategy.ActiveKey currentActiveKey = keyStore2activeKey.get(keyStore);
081    
082                    if (currentActiveKey == null || currentActiveKey.getActiveToExcl().compareTo(request.getTimestamp()) <= 0) {
083                            DateDependentKeyStrategy keyStrategy = new DateDependentKeyStrategy(keyStore);
084                            DateDependentKeyStrategy.ActiveKey newActiveKey = keyStrategy.getActiveKey(
085                                            session.getUserName(), session.getPassword(), request.getTimestamp()
086                            );
087                            if (newActiveKey == null)
088                                    throw new IllegalStateException("keyStrategy.getActiveKey(...) returned null!");
089    
090                            keyStore2activeKey.put(keyStore, newActiveKey);
091                            currentActiveKey = newActiveKey;
092                    }
093    
094                    byte[] key = keyStore.getKey(session.getUserName(), session.getPassword(), currentActiveKey.getKeyID());
095                    byte[] keyEncodedEncrypted = KeyEncryptionUtil.encryptKey(key, request.getKeyEncryptionTransformation(), request.getKeyEncryptionPublicKey());
096                    return new GetActiveEncryptionKeyResponse(
097                                    request,
098                                    currentActiveKey.getKeyID(), keyEncodedEncrypted, currentActiveKey.getActiveToExcl()
099                    );
100            }
101    
102    }