1 13 14 package org.ejbca.core.ejb.protect; 15 16 import java.io.UnsupportedEncodingException ; 17 import java.security.InvalidKeyException ; 18 import java.security.NoSuchAlgorithmException ; 19 import java.security.NoSuchProviderException ; 20 import java.sql.PreparedStatement ; 21 import java.util.Date ; 22 23 import javax.crypto.Mac; 24 import javax.crypto.SecretKey; 25 import javax.crypto.spec.SecretKeySpec; 26 import javax.ejb.EJBException ; 27 import javax.ejb.FinderException ; 28 import javax.ejb.ObjectNotFoundException ; 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 105 public class TableProtectSessionBean extends BaseSessionBean { 106 107 108 private static final InternalResources intres = InternalResources.getInstance(); 109 110 private static final String HMAC_ALG = "HMac-SHA256"; 111 112 113 private TableProtectDataLocalHome protectentryhome; 114 115 private String keyType = null; 116 private String keyRef = null; 117 private String key = null; 118 boolean enabled = false; 119 boolean warnOnMissingRow = true; 120 121 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 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 en = getLocator().getString("java:comp/env/enabled"); 137 if (StringUtils.equalsIgnoreCase(en, "true") && key != null) { 138 enabled = true; 139 } 140 String warn = getLocator().getString("java:comp/env/warnOnMissingRow"); 141 if (StringUtils.equalsIgnoreCase(warn, "false")) { 142 warnOnMissingRow = false; 143 } 144 } catch (Exception e) { 145 throw new EJBException (e); 146 } 147 } 148 149 150 159 public void protectExternal(Admin admin, Protectable entry, String dataSource) { 160 if (!enabled) { 161 return; 162 } 163 int hashVersion = entry.getHashVersion(); 164 String dbKey = entry.getDbKeyString(); 165 String dbType = entry.getEntryType(); 166 debug("Protecting entry, type: "+dbType+", with key: "+dbKey); 167 String hash; 168 try { 169 hash = entry.getHash(); 170 String signature = createHmac(key, HMAC_ALG, hash); 171 String 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 e) { 177 178 } 179 if (id != null) { 180 String 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 ()).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 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 ()).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 e) { 196 String msg = intres.getLocalizedMessage("protect.errorcreate", dbType, dbKey); 197 error(msg, e); 198 } 199 } 200 } catch (Exception e) { 201 String msg = intres.getLocalizedMessage("protect.errorcreate", dbType, dbKey); 202 error(msg, e); 203 } 204 } 205 206 215 public void protect(Admin admin, Protectable entry) { 216 if (!enabled) { 217 return; 218 } 219 int hashVersion = entry.getHashVersion(); 220 String dbKey = entry.getDbKeyString(); 221 String dbType = entry.getEntryType(); 222 debug("Protecting entry, type: "+dbType+", with key: "+dbKey); 223 String hash; 224 try { 225 hash = entry.getHash(); 226 String signature = createHmac(key, HMAC_ALG, hash); 227 String id = GUIDGenerator.generateGUID(this); 228 try { 229 TableProtectDataLocal data = protectentryhome.findByDbTypeAndKey(dbType, dbKey); 230 if (data != null) { 231 String 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 ()).getTime()); 238 data.setDbKey(dbKey); 239 data.setDbType(dbType); 240 data.setKeyRef(keyRef); 241 data.setKeyType(keyType); 242 } 243 } catch (FinderException e1) { 244 try { 245 protectentryhome.create(id, hashVersion, HMAC_ALG, hash, signature, new Date (), dbKey, dbType, keyRef, keyType); 246 } catch (Exception e) { 247 String msg = intres.getLocalizedMessage("protect.errorcreate", dbType, dbKey); 248 error(msg, e); 249 } 250 } 251 } catch (Exception e) { 252 String msg = intres.getLocalizedMessage("protect.errorcreate", dbType, dbKey); 253 error(msg, e); 254 } 255 } 257 267 public TableVerifyResult verify(Protectable entry) { 268 TableVerifyResult ret = new TableVerifyResult(); 269 if (!enabled) { 270 return ret; 271 } 272 String alg = HMAC_ALG; 273 String dbKey = entry.getDbKeyString(); 274 String 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 hash = entry.getHash(hashVersion); 280 if (!StringUtils.equals(keyRef, data.getKeyRef())) { 281 ret.setResultCode(TableVerifyResult.VERIFY_NO_KEY); 282 String 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 msg = intres.getLocalizedMessage("protect.errorverifyalg", dbType, dbKey); 287 error(msg); 288 } else { 289 if (log.isDebugEnabled()) { 291 log.debug("Hash is: "+hash); 292 } 293 String 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 msg = intres.getLocalizedMessage("protect.errorverify", dbType, dbKey); 300 error(msg); 301 } else { 302 if (!StringUtils.equals(hash, data.getHash())) { 304 ret.setResultCode(TableVerifyResult.VERIFY_WRONG_HASH); 305 String msg = intres.getLocalizedMessage("protect.errorverifywronghash", dbType, dbKey); 306 error(msg); 307 } 308 } 309 } 310 } catch (ObjectNotFoundException e) { 311 if (warnOnMissingRow) { 312 String msg = intres.getLocalizedMessage("protect.errorverifynorow", dbType, dbKey); 313 error(msg); 314 } 315 ret.setResultCode(TableVerifyResult.VERIFY_NO_ROW); 316 }catch (Exception e) { 317 String msg = intres.getLocalizedMessage("protect.errorverifycant", dbType, dbKey); 318 error(msg, e); 319 } 320 return ret; 321 } 323 private String createHmac(String pwd, String alg, String data) throws NoSuchAlgorithmException , NoSuchProviderException , UnsupportedEncodingException , InvalidKeyException { 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 (Hex.encode(out)); 332 } 333 334 protected class SelectProtectPreparer implements JDBCUtil.Preparer { 335 private final String dbType; 336 private final String dbKey; 337 public SelectProtectPreparer(final String dbType, final String dbKey) { 338 super(); 339 this.dbType = dbType; 340 this.dbKey = dbKey; 341 } 342 public void prepare(PreparedStatement ps) throws Exception { 343 ps.setString(1, dbType); 344 ps.setString(2, dbKey); 345 } 346 public String getInfoString() { 347 return "Select:, dbKey:"+dbKey+", dbType: "+dbType; 348 } 349 } 350 351 protected class ProtectPreparer implements JDBCUtil.Preparer { 352 private final String id; 353 private final int version; 354 private final int hashVersion; 355 private final String alg; 356 private final String hash; 357 private final String signature; 358 private final long time; 359 private final String dbKey; 360 private final String dbType; 361 private final String keyRef; 362 private final String keyType; 363 364 public ProtectPreparer(final String id, final int version, final int hashVersion, final String alg, final String hash, final String signature, final long time, final String dbKey, final String dbType, final String keyRef, final String 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 ps) throws Exception { 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 getInfoString() { 392 return "Store:, id: "+id+", dbKey:"+dbKey+", dbType: "+dbType; 393 } 394 } 395 396 397 } | Popular Tags |