KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ejbca > core > ejb > protect > TableProtectSessionBean


1 /*************************************************************************
2  * *
3  * EJBCA: The OpenSource Certificate Authority *
4  * *
5  * This software is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU Lesser General Public *
7  * License as published by the Free Software Foundation; either *
8  * version 2.1 of the License, or any later version. *
9  * *
10  * See terms of license at gnu.org. *
11  * *
12  *************************************************************************/

13
14 package org.ejbca.core.ejb.protect;
15
16 import java.io.UnsupportedEncodingException JavaDoc;
17 import java.security.InvalidKeyException JavaDoc;
18 import java.security.NoSuchAlgorithmException JavaDoc;
19 import java.security.NoSuchProviderException JavaDoc;
20 import java.sql.PreparedStatement JavaDoc;
21 import java.util.Date JavaDoc;
22
23 import javax.crypto.Mac;
24 import javax.crypto.SecretKey;
25 import javax.crypto.spec.SecretKeySpec;
26 import javax.ejb.EJBException JavaDoc;
27 import javax.ejb.FinderException JavaDoc;
28 import javax.ejb.ObjectNotFoundException JavaDoc;
29
30 import org.apache.commons.lang.StringUtils;
31 import org.bouncycastle.util.encoders.Hex;
32 import org.ejbca.core.ejb.BaseSessionBean;
33 import org.ejbca.core.model.InternalResources;
34 import org.ejbca.core.model.log.Admin;
35 import org.ejbca.core.model.protect.Protectable;
36 import org.ejbca.core.model.protect.TableVerifyResult;
37 import org.ejbca.util.CertTools;
38 import org.ejbca.util.GUIDGenerator;
39 import org.ejbca.util.JDBCUtil;
40 import org.ejbca.util.StringTools;
41
42
43 /** For some setups there are requirements for integrity protection of
44  * database rows.
45  *
46  * @ejb.bean
47  * display-name="TableProtectSB"
48  * name="TableProtectSession"
49  * jndi-name="TableProtectSession"
50  * local-jndi-name="TableProtectSessionLocal"
51  * view-type="both"
52  * type="Stateless"
53  * transaction-type="Container"
54  *
55  * @weblogic.enable-call-by-reference True
56  *
57  * @ejb.env-entry description="Enable or disable protection alltogether"
58  * name="enabled"
59  * type="java.lang.String"
60  * value="${protection.enabled}"
61  *
62  * @ejb.env-entry description="If we should warn if a protection row is missing"
63  * name="warnOnMissingRow"
64  * type="java.lang.String"
65  * value="${protection.warnonmissingrow}"
66  *
67  * @ejb.env-entry description="Key (reference or actual key, depending on type) for protection"
68  * name="keyRef"
69  * type="java.lang.String"
70  * value="${protection.keyref}"
71  *
72  * @ejb.env-entry description="Key for reference above"
73  * name="${protection.keyref}"
74  * type="java.lang.String"
75  * value="${protection.key}"
76  *
77  * @ejb.env-entry description="Key type, ENC_SOFT_HMAC or SOFT_HMAC"
78  * name="keyType"
79  * type="java.lang.String"
80  * value="${protection.keytype}"
81  *
82  * @ejb.ejb-external-ref
83  * description="The Protect Entry Data entity bean"
84  * view-type="local"
85  * ref-name="ejb/TableProtectDataLocal"
86  * type="Entity"
87  * home="org.ejbca.core.ejb.protect.TableProtectDataLocalHome"
88  * business="org.ejbca.core.ejb.protect.TableProtectDataLocal"
89  * link="TableProtectData"
90  *
91  * @ejb.home
92  * extends="javax.ejb.EJBHome"
93  * local-extends="javax.ejb.EJBLocalHome"
94  * local-class="org.ejbca.core.ejb.protect.TableProtectSessionLocalHome"
95  * remote-class="org.ejbca.core.ejb.protect.TableProtectSessionHome"
96  *
97  * @ejb.interface
98  * extends="javax.ejb.EJBObject"
99  * local-extends="javax.ejb.EJBLocalObject"
100  * local-class="org.ejbca.core.ejb.protect.TableProtectSessionLocal"
101  * remote-class="org.ejbca.core.ejb.protect.TableProtectSessionRemote"
102  *
103  * @version $Id: TableProtectSessionBean.java,v 1.6 2006/12/13 10:33:09 anatom Exp $
104  */

105 public class TableProtectSessionBean extends BaseSessionBean {
106
107     /** Internal localization of logs and errors */
108     private static final InternalResources intres = InternalResources.getInstance();
109
110     private static final String JavaDoc HMAC_ALG = "HMac-SHA256";
111     
112     /** The home interface of LogEntryData entity bean */
113     private TableProtectDataLocalHome protectentryhome;
114
115     private String JavaDoc keyType = null;
116     private String JavaDoc keyRef = null;
117     private String JavaDoc key = null;
118     boolean enabled = false;
119     boolean warnOnMissingRow = true;
120     
121     /**
122      * Default create for SessionBean without any creation Arguments.
123      */

124     public void ejbCreate() {
125         try {
126             CertTools.installBCProvider();
127             protectentryhome = (TableProtectDataLocalHome) getLocator().getLocalHome(TableProtectDataLocalHome.COMP_NAME);
128             keyType = getLocator().getString("java:comp/env/keyType");
129             keyRef = getLocator().getString("java:comp/env/keyRef");
130             String JavaDoc tmpkey = getLocator().getString("java:comp/env/"+keyRef);
131             if (StringUtils.equalsIgnoreCase(keyType, "ENC_SOFT_HMAC")) {
132                 key = StringTools.pbeDecryptStringWithSha256Aes192(tmpkey);
133             } else {
134                 key = tmpkey;
135             }
136             String JavaDoc en = getLocator().getString("java:comp/env/enabled");
137             if (StringUtils.equalsIgnoreCase(en, "true") && key != null) {
138                 enabled = true;
139             }
140             String JavaDoc warn = getLocator().getString("java:comp/env/warnOnMissingRow");
141             if (StringUtils.equalsIgnoreCase(warn, "false")) {
142                 warnOnMissingRow = false;
143             }
144         } catch (Exception JavaDoc e) {
145             throw new EJBException JavaDoc(e);
146         }
147     }
148
149
150     /**
151      * Store a protection entry in an external, remote database.
152      *
153      * @param admin the administrator performing the event.
154      * @param Protectable the object beeing protected
155      *
156      * @ejb.interface-method
157      * @ejb.transaction type="Required"
158      */

159     public void protectExternal(Admin admin, Protectable entry, String JavaDoc dataSource) {
160         if (!enabled) {
161             return;
162         }
163         int hashVersion = entry.getHashVersion();
164         String JavaDoc dbKey = entry.getDbKeyString();
165         String JavaDoc dbType = entry.getEntryType();
166         debug("Protecting entry, type: "+dbType+", with key: "+dbKey);
167         String JavaDoc hash;
168         try {
169             hash = entry.getHash();
170             String JavaDoc signature = createHmac(key, HMAC_ALG, hash);
171             String JavaDoc id = null;
172             try {
173                 SelectProtectPreparer prep = new SelectProtectPreparer(dbType, dbKey);
174                 id = JDBCUtil.executeSelectString("SELECT id FROM TableProtectData where dbType=? and dbKey=?",
175                         prep, dataSource );
176             } catch (Exception JavaDoc e) {
177                 
178             }
179             if (id != null) {
180                 String JavaDoc msg = intres.getLocalizedMessage("protect.rowexistsupdate", dbType, dbKey);
181                 info(msg);
182                 ProtectPreparer uprep = new ProtectPreparer(id, TableProtectDataBean.CURRENT_VERSION, hashVersion, HMAC_ALG, hash, signature, (new Date JavaDoc()).getTime(), dbKey, dbType, keyRef,keyType);
183                 try {
184                     JDBCUtil.execute( "UPDATE TableProtectData SET version=?,hashVersion=?,protectionAlg=?,hash=?,signature=?,time=?,dbKey=?,dbType=?,keyRef=?,keyType=? WHERE id=?",
185                             uprep, dataSource );
186                 } catch (Exception JavaDoc ue) {
187                     error("PROTECT ERROR: can not create protection row for entry type: "+dbType+", with key: "+dbKey, ue);
188                 }
189             } else {
190                 id = GUIDGenerator.generateGUID(this);
191                 try {
192                     ProtectPreparer prep = new ProtectPreparer(id, TableProtectDataBean.CURRENT_VERSION, hashVersion, HMAC_ALG, hash, signature, (new Date JavaDoc()).getTime(), dbKey, dbType, keyRef,keyType);
193                     JDBCUtil.execute( "INSERT INTO TableProtectData (version,hashVersion,protectionAlg,hash,signature,time,dbKey,dbType,keyRef,keyType,id) VALUES (?,?,?,?,?,?,?,?,?,?,?)",
194                             prep, dataSource );
195                 } catch (Exception JavaDoc e) {
196                     String JavaDoc msg = intres.getLocalizedMessage("protect.errorcreate", dbType, dbKey);
197                     error(msg, e);
198                 }
199             }
200         } catch (Exception JavaDoc e) {
201             String JavaDoc msg = intres.getLocalizedMessage("protect.errorcreate", dbType, dbKey);
202             error(msg, e);
203         }
204     }
205     
206     /**
207      * Store a protection entry.
208      *
209      * @param admin the administrator performing the event.
210      * @param Protectable the object beeing protected
211      *
212      * @ejb.interface-method
213      * @ejb.transaction type="Required"
214      */

215     public void protect(Admin admin, Protectable entry) {
216         if (!enabled) {
217             return;
218         }
219         int hashVersion = entry.getHashVersion();
220         String JavaDoc dbKey = entry.getDbKeyString();
221         String JavaDoc dbType = entry.getEntryType();
222         debug("Protecting entry, type: "+dbType+", with key: "+dbKey);
223         String JavaDoc hash;
224         try {
225             hash = entry.getHash();
226             String JavaDoc signature = createHmac(key, HMAC_ALG, hash);
227             String JavaDoc id = GUIDGenerator.generateGUID(this);
228             try {
229                 TableProtectDataLocal data = protectentryhome.findByDbTypeAndKey(dbType, dbKey);
230                 if (data != null) {
231                     String JavaDoc msg = intres.getLocalizedMessage("protect.rowexistsupdate", dbType, dbKey);
232                     info(msg);
233                     data.setHashVersion(hashVersion);
234                     data.setHash(hash);
235                     data.setProtectionAlg(HMAC_ALG);
236                     data.setSignature(signature);
237                     data.setTime((new Date JavaDoc()).getTime());
238                     data.setDbKey(dbKey);
239                     data.setDbType(dbType);
240                     data.setKeyRef(keyRef);
241                     data.setKeyType(keyType);
242                 }
243             } catch (FinderException JavaDoc e1) {
244                 try {
245                     protectentryhome.create(id, hashVersion, HMAC_ALG, hash, signature, new Date JavaDoc(), dbKey, dbType, keyRef, keyType);
246                 } catch (Exception JavaDoc e) {
247                     String JavaDoc msg = intres.getLocalizedMessage("protect.errorcreate", dbType, dbKey);
248                     error(msg, e);
249                 }
250             }
251         } catch (Exception JavaDoc e) {
252             String JavaDoc msg = intres.getLocalizedMessage("protect.errorcreate", dbType, dbKey);
253             error(msg, e);
254         }
255     } // protect
256

257     /**
258      * Verifies a protection entry.
259      *
260      * @param admin the administrator performing the event.
261      * @param Protectable the object beeing verified
262      * @return TableVerifyResult, never null
263      *
264      * @ejb.interface-method
265      * @ejb.transaction type="Supports"
266      */

267     public TableVerifyResult verify(Protectable entry) {
268         TableVerifyResult ret = new TableVerifyResult();
269         if (!enabled) {
270             return ret;
271         }
272         String JavaDoc alg = HMAC_ALG;
273         String JavaDoc dbKey = entry.getDbKeyString();
274         String JavaDoc dbType = entry.getEntryType();
275         debug("Verifying entry, type: "+dbType+", with key: "+dbKey);
276         try {
277             TableProtectDataLocal data = protectentryhome.findByDbTypeAndKey(dbType, dbKey);
278             int hashVersion = data.getHashVersion();
279             String JavaDoc hash = entry.getHash(hashVersion);
280             if (!StringUtils.equals(keyRef, data.getKeyRef())) {
281                 ret.setResultCode(TableVerifyResult.VERIFY_NO_KEY);
282                 String JavaDoc msg = intres.getLocalizedMessage("protect.errorverifynokey", dbType, dbKey);
283                 error(msg);
284             } else if (!StringUtils.equals(alg, data.getProtectionAlg())) {
285                     ret.setResultCode(TableVerifyResult.VERIFY_INCOMPATIBLE_ALG);
286                     String JavaDoc msg = intres.getLocalizedMessage("protect.errorverifyalg", dbType, dbKey);
287                     error(msg);
288             } else {
289                 // Create a new signature on the passed in object, and compare it with the one we have stored in the db'
290
if (log.isDebugEnabled()) {
291                     log.debug("Hash is: "+hash);
292                 }
293                 String JavaDoc signature = createHmac(key, alg, hash);
294                 if (log.isDebugEnabled()) {
295                     log.debug("Signature is: "+signature);
296                 }
297                 if (!StringUtils.equals(signature, data.getSignature())) {
298                     ret.setResultCode(TableVerifyResult.VERIFY_FAILED);
299                     String JavaDoc msg = intres.getLocalizedMessage("protect.errorverify", dbType, dbKey);
300                     error(msg);
301                 } else {
302                     // This can actually never happen
303
if (!StringUtils.equals(hash, data.getHash())) {
304                         ret.setResultCode(TableVerifyResult.VERIFY_WRONG_HASH);
305                         String JavaDoc msg = intres.getLocalizedMessage("protect.errorverifywronghash", dbType, dbKey);
306                         error(msg);
307                     }
308                 }
309             }
310         } catch (ObjectNotFoundException JavaDoc e) {
311             if (warnOnMissingRow) {
312                 String JavaDoc msg = intres.getLocalizedMessage("protect.errorverifynorow", dbType, dbKey);
313                 error(msg);
314             }
315             ret.setResultCode(TableVerifyResult.VERIFY_NO_ROW);
316         }catch (Exception JavaDoc e) {
317             String JavaDoc msg = intres.getLocalizedMessage("protect.errorverifycant", dbType, dbKey);
318             error(msg, e);
319         }
320         return ret;
321     } // verify
322

323     private String JavaDoc createHmac(String JavaDoc pwd, String JavaDoc alg, String JavaDoc data) throws NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc, UnsupportedEncodingException JavaDoc, InvalidKeyException JavaDoc {
324         Mac mac = Mac.getInstance(alg, "BC");
325         SecretKey key = new SecretKeySpec(pwd.getBytes("UTF-8"), alg);
326         mac.init(key);
327         mac.reset();
328         byte[] dataBytes = data.getBytes("UTF-8");
329         mac.update(dataBytes, 0, dataBytes.length);
330         byte[] out = mac.doFinal();
331         return new String JavaDoc(Hex.encode(out));
332     }
333
334     protected class SelectProtectPreparer implements JDBCUtil.Preparer {
335         private final String JavaDoc dbType;
336         private final String JavaDoc dbKey;
337         public SelectProtectPreparer(final String JavaDoc dbType, final String JavaDoc dbKey) {
338             super();
339             this.dbType = dbType;
340             this.dbKey = dbKey;
341         }
342         public void prepare(PreparedStatement JavaDoc ps) throws Exception JavaDoc {
343             ps.setString(1, dbType);
344             ps.setString(2, dbKey);
345         }
346         public String JavaDoc getInfoString() {
347             return "Select:, dbKey:"+dbKey+", dbType: "+dbType;
348         }
349     }
350
351     protected class ProtectPreparer implements JDBCUtil.Preparer {
352         private final String JavaDoc id;
353         private final int version;
354         private final int hashVersion;
355         private final String JavaDoc alg;
356         private final String JavaDoc hash;
357         private final String JavaDoc signature;
358         private final long time;
359         private final String JavaDoc dbKey;
360         private final String JavaDoc dbType;
361         private final String JavaDoc keyRef;
362         private final String JavaDoc keyType;
363         
364         public ProtectPreparer(final String JavaDoc id, final int version, final int hashVersion, final String JavaDoc alg, final String JavaDoc hash, final String JavaDoc signature, final long time, final String JavaDoc dbKey, final String JavaDoc dbType, final String JavaDoc keyRef, final String JavaDoc keyType) {
365             super();
366             this.id = id;
367             this.version = version;
368             this.hashVersion = hashVersion;
369             this.alg = alg;
370             this.hash = hash;
371             this.signature = signature;
372             this.time = time;
373             this.dbKey = dbKey;
374             this.dbType = dbType;
375             this.keyRef = keyRef;
376             this.keyType = keyType;
377         }
378         public void prepare(PreparedStatement JavaDoc ps) throws Exception JavaDoc {
379             ps.setInt(1, version);
380             ps.setInt(2, hashVersion);
381             ps.setString(3, alg);
382             ps.setString(4, hash);
383             ps.setString(5, signature);
384             ps.setLong(6, time);
385             ps.setString(7, dbKey);
386             ps.setString(8, dbType);
387             ps.setString(9, keyRef);
388             ps.setString(10, keyType);
389             ps.setString(11,id);
390         }
391         public String JavaDoc getInfoString() {
392             return "Store:, id: "+id+", dbKey:"+dbKey+", dbType: "+dbType;
393         }
394     }
395
396
397 } // TableProtectSessionBean
398
Popular Tags