Skip to content

Commit

Permalink
Implement applet firewall
Browse files Browse the repository at this point in the history
- implement applet firewall with java.reflect proxy. Fixes licel#60
- allow externalAccess. Fixes licel#45
  • Loading branch information
robertbachmann committed Sep 6, 2017
1 parent ade8ee9 commit 52c1cf3
Show file tree
Hide file tree
Showing 12 changed files with 538 additions and 53 deletions.
91 changes: 91 additions & 0 deletions src/main/java/com/licel/jcardsim/base/AppletContextManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.licel.jcardsim.base;

import java.util.Stack;
import javacard.framework.AID;

public final class AppletContextManager {
/** the current context */
private Stack<AppletContext> contextStack = new Stack<AppletContext>();

public AppletContextManager() {
}

/**
* Clear the context.
*/
public void clear() {
contextStack.clear();
}

/**
* Enter a context
* @param packageAID packageAID
* @param appletAID appletAID
*/
public void enterContext(AID packageAID, AID appletAID) {
contextStack.push(new AppletContext(packageAID, appletAID));
}

/**
* Leave a context
*/
public void leaveContext() {
if (!contextStack.isEmpty()) {
contextStack.pop();
}
}

/**
* @return the AID of the active applet or <code>null</code>.
*/
public AID getActiveAID() {
return contextStack.empty() ? null : contextStack.peek().appletAID;
}

/**
* @return the AID of the active applet or <code>null</code>.
*/
public AID getActivePackageAID() {
return contextStack.empty() ? null : contextStack.peek().packageAID;
}


/**
* @return the AID of the previous applet or <code>null</code>.
*/
public AID getPreviousContextAID() {
if (contextStack.size() <= 1) {
return null;
}
final AID currentPackage = contextStack.peek().packageAID;
for (int i = contextStack.size() - 1; i >= 0; --i) {
final AID p = contextStack.get(i).packageAID;
if (!p.equals(currentPackage)) {
return contextStack.get(i).appletAID;
}
}
return null;
}

private static final class AppletContext {
public final AID packageAID;
public final AID appletAID;

public AppletContext(AID packageAID, AID appletAID) {
if (packageAID == null)
throw new NullPointerException("packageAID");
if (appletAID == null)
throw new NullPointerException("appletAID");
this.packageAID = packageAID;
this.appletAID = appletAID;
}

@Override
public String toString() {
return "AppletContext{" +
"packageAID=" + packageAID +
", appletAID=" + appletAID +
'}';
}
}
}
95 changes: 95 additions & 0 deletions src/main/java/com/licel/jcardsim/base/AppletFirewall.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package com.licel.jcardsim.base;

import com.licel.jcardsim.utils.AIDUtil;
import com.licel.jcardsim.utils.Supplier;
import javacard.framework.AID;
import javacard.framework.Shareable;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;

public class AppletFirewall {
private final Shareable firewalledShareable;
private final AID packageAID;
private final AID appletAID;
private final Set<Method> whiteList;
private final Supplier<AppletContextManager> appletContextManagerSupplier;
private final Shareable shareable;

public AppletFirewall(Supplier<AppletContextManager> appletContextManagerSupplier, Shareable shareable) {
if (shareable == null) {
throw new NullPointerException("shareable");
}

final Class<?> shareableClass = shareable.getClass();
final AppletContextManager appletContextManager = appletContextManagerSupplier.get();
final Class[] interfaces = allInterfaces(shareableClass);

this.appletContextManagerSupplier = appletContextManagerSupplier;
this.shareable = shareable;
this.packageAID = appletContextManager.getActivePackageAID();
this.appletAID = appletContextManager.getActiveAID();
this.whiteList = buildWhiteList(interfaces);

this.firewalledShareable = (Shareable) Proxy.newProxyInstance(shareableClass.getClassLoader(),
interfaces,
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return AppletFirewall.this.invoke(proxy, method, args);
}
});
}

protected static Class[] allInterfaces(final Class<?> shareableClass) {
final List<Class> interfaces = new ArrayList<Class>();
Class<?> currentClass = shareableClass;
while (!currentClass.equals(Object.class)) {
Collections.addAll(interfaces, currentClass.getInterfaces());
currentClass = currentClass.getSuperclass();
}
return interfaces.toArray(new Class[interfaces.size()]);
}

protected static Set<Method> buildWhiteList(final Class[] interfaces) {
final Set<Method> whiteList = new HashSet<Method>();
for (Class anInterface : interfaces) {
if (Shareable.class.isAssignableFrom(anInterface)) {
Collections.addAll(whiteList, anInterface.getMethods());
}
}
return whiteList;
}

protected Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (proxy != firewalledShareable) {
throw new AssertionError("Wrong proxy");
}

final AppletContextManager contextManager = appletContextManagerSupplier.get();
final AID callerPackage = contextManager.getActivePackageAID();

if (method.getDeclaringClass().equals(Object.class) && method.getName().equals("toString")) {
return "AppletFirewallProxy bound to " + AIDUtil.toString(packageAID) + " for " + shareable;
}
if (!packageAID.equals(callerPackage)) {
if (!whiteList.contains(method)) {
throw new SecurityException("Calling this method is not allowed");
}
contextManager.enterContext(packageAID, appletAID);
try {
return method.invoke(shareable, args);
}
finally {
contextManager.leaveContext();
}
} else {
return method.invoke(shareable, args);
}
}

public Shareable getShareable() {
return firewalledShareable;
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/licel/jcardsim/base/Simulator.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public AID loadApplet(AID aid, String appletClassName) throws SystemException {
*/
public AID loadApplet(AID aid, Class<? extends Applet> appletClass) throws SystemException {
synchronized (runtime) {
runtime.loadApplet(aid, requireExtendsApplet(appletClass));
runtime.wrapAppletIntoLoadFile(aid, requireExtendsApplet(appletClass));
}
return aid;
}
Expand Down
Loading

0 comments on commit 52c1cf3

Please sign in to comment.