[Fedora-directory-commits] coolkey/applet/src/com/redhat/ckey/applet ASN1.java, NONE, 1.1 CardEdge.java, NONE, 1.1 MemoryManager.java, NONE, 1.1 ObjectManager.java, NONE, 1.1

Robert Relyea (rrelyea) fedora-directory-commits at redhat.com
Fri Aug 18 18:37:16 UTC 2006


Author: rrelyea

Update of /cvs/dirsec/coolkey/applet/src/com/redhat/ckey/applet
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv14460/src/com/redhat/ckey/applet

Added Files:
	ASN1.java CardEdge.java MemoryManager.java ObjectManager.java 
Log Message:


Coolkey applet



--- NEW FILE ASN1.java ---
//  SmartCard Applet
//      Authors:          Robert Relyea     <rrelyea at redhat.com>
//      Package:          CardEdgeApplet
//      Description:      CardEdge implementation with JavaCard
//
// BEGIN LICENSE BLOCK
// Copyright (C) 2006 Red Hat, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// Changes to this license can be made only by the copyright author with
// explicit written consent.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Alternatively, the contents of this file may be used under the terms of
// the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
// case the provisions of the LGPL are applicable instead of those above. If
// you wish to allow use of your version of this file only under the terms
// of the LGPL, and not to allow others to use your version of this file
// under the terms of the BSD license, indicate your decision by deleting
// the provisions above and replace them with the notice and other
// provisions required by the LGPL. If you do not delete the provisions
// above, a recipient may use your version of this file under the terms of
// either the BSD license or the LGPL.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
// END LICENSE_BLOCK

package com.redhat.nkey.applet;

import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.Util;

/**
 * ASN1 parser Class
 *
 * <p>This Simplistic ASN.1 parser does not interpret tags, it simply finds
 * elements based on where their fields are supposed to wind up at. </p>
 *
 *
 * Object fields:
 * <pre>
 *    short[] newSize; // way to get around java's restrictions on pass by ref. 
 *    byte[] data
 * </pre>
 *
 * @author Robert Relyea
 * @version 0.0.1
 *
 */
public class ASN1
{
    public static final short SW_BAD_DER_DATA = (short)0x9cd0;
    private final short NEXT = 0;
    private final short SIZE = 1;
    private final short END  = 2;
    private short[] params;

    public ASN1() 
    {
	params=JCSystem.makeTransientShortArray((short)3,
						JCSystem.CLEAR_ON_DESELECT);
    }
  
    public short GetEnd()
    {
	return params[END];
    } 

    public short GetSize()
    {
	return params[SIZE];
    } 

    public short GetNext()
    {
	return params[NEXT];
    } 

    public byte GetTag(byte buf[], short offset, short end)
    {
	if (end <= offset) {
	    ISOException.throwIt(SW_BAD_DER_DATA);
	}
	return buf[offset];
    }
	
    public short Unwrap(byte buf[], short offset, short end, short dbg)
    {
	byte tag;
	byte len;
	short length = 0;

	if (end < (short)(offset+2)) {
	    ISOException.throwIt(SW_BAD_DER_DATA);
	}
	tag = buf[offset++];
	if (tag == 0) {
	    ISOException.throwIt(SW_BAD_DER_DATA);
	}
	len = buf[offset++];
	length = Util.makeShort((byte)0,len);

	if ((len & 0x80) != 0) {
	    short count = Util.makeShort((byte)0,(byte)(len & 0x7f));
	    if (end < (short)(offset+count)) {
	        ISOException.throwIt(SW_BAD_DER_DATA);
	    }
	    if (count > 2) {
	        ISOException.throwIt(SW_BAD_DER_DATA);
	    }
            length = 0;
	    while (count-- > 0) {
		length = (short)((length << 8) 
				| Util.makeShort((byte)0,buf[offset++]));
	    }
	}
	params[SIZE] = length;
	params[NEXT] = ((short)(offset+length));
	params[END] = ((short)(offset+length));
	return offset;
    }

    public short Skip(byte buf[], short offset, short end, short dbg)
    {
	Unwrap(buf,offset,end,dbg);
	return params[NEXT];
    }

    public short UnwrapBitString(byte buf[], short offset, short end, short dbg)
    {
	if (buf[offset] != 0) {
	    ISOException.throwIt(SW_BAD_DER_DATA);
	}
	if (end < (short)(offset+1)) {
	    ISOException.throwIt(SW_BAD_DER_DATA);
	}
	params[SIZE]--;
	return (short)(offset+1);
    }

    public short Signed2Unsigned(byte buf[], short offset, short end, short dbg)
    {
	short startOffset = offset;
	short startSize=params[SIZE];
	for (; offset < end && buf[offset] == 0 ; offset++){
	    params[SIZE]--;
	}
	if (offset >= end) {
	    ISOException.throwIt(SW_BAD_DER_DATA);
	}
	return offset;
    }
}




--- NEW FILE CardEdge.java ---
//  MUSCLE SmartCard Development
//      Authors: Tommaso Cucinotta <cucinotta at sssup.it>
//	         David Corcoran    <corcoran at linuxnet.com>
//	         Ludovic Rousseau  <ludovic.rousseau at free.fr>
//	         Jamie Nicolson    <nicolson at netscape.com>
//	         Robert Relyea     <rrelyea at redhat.com>
//	         Nelson Bolyard    <nelsonb at netscape.com>
//      Package:         CardEdgeApplet
//      Description:      CardEdge implementation with JavaCard
//      Protocol Authors: Tommaso Cucinotta <cucinotta at sssup.it>
//	                  David Corcoran <corcoran at linuxnet.com>
//      Modified:
//	                  Eirik Herskedal <ehersked at cs.purdue.edu>
//
// BEGIN LICENSE BLOCK
// Copyright (C) 1999-2002 David Corcoran <corcoran at linuxnet.com>
// Copyright (C) 2006 Red Hat, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// Changes to this license can be made only by the copyright author with
// explicit written consent.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Alternatively, the contents of this file may be used under the terms of
// the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
// case the provisions of the LGPL are applicable instead of those above. If
// you wish to allow use of your version of this file only under the terms
// of the LGPL, and not to allow others to use your version of this file
// under the terms of the BSD license, indicate your decision by deleting
// the provisions above and replace them with the notice and other
// provisions required by the LGPL. If you do not delete the provisions
// above, a recipient may use your version of this file under the terms of
// either the BSD license or the LGPL.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
// END LICENSE_BLOCK

package com.redhat.nkey.applet;

import javacard.framework.*;
import javacard.security.*;
import javacardx.crypto.Cipher;

import visa.openplatform.ProviderSecurityDomain;
import visa.openplatform.OPSystem;

// Referenced classes of package com.redhat.nkey.applet:
//	    MemoryManager, ObjectManager, ASN1

/**
 * Implements MUSCLE's Card Edge Specification.
 * 
 * <p>TODO:
 * 
 * <ul>
 *  <li>Allows maximum number of keys and PINs and total mem to be specified at the instantiation moment.</li>
 * 
 *  <li>How do transactions fit in the methods?</li>
 *  <li>Where should we issue begin/end transaction?</li>
 *  <li>Should we ever abort transaction? Where?</li>
 *  <li>Everytime there is an <tt>"if (avail < )"</tt> check, call <tt>ThrowDeleteObjects()</tt>.</li>
 * </ul>
 * </p>
 * 
 * <p>NOTES:
 * 
 * <ul>
 *  <li>C preprocessor flags:
 *   <ul>
 *    <li>Encryption algorithms: WITH_RSA, WITH_DSA, WITH_DES, WITH_3DES</li>
 *    <li>ComputeCrypt directions: WITH_ENCRYPT, WITH_DECRYPT, WITH_SIGN</li>
 *    <li>Enable/Disable External Authenticate: WITH_EXT_AUTH</li>
 *    <li>Enable/Disable PIN Policy enforcement: WITH_PIN_POLICY</li>
 *   </ul>
*  </li>
 *  <li>C preprocessor defines:
 *   <ul>
 *    <li>JAVA_PACKAGE: The name of Java package for this Applet</li>
 *    <li>CardEdge: The name of Java class for the Applet</li>
 *   </ul>
 *  </li>
 * </ul>
 * </p>
 *
 * @author Tommaso Cucinotta
 * @author David Corcoran
 * @author Ludovic Rousseau
 * @version 0.9.10
 */


public class CardEdge extends Applet
{
    private static final byte ZEROB = 0;
    private static final byte MAX_NUM_KEYS = 8;
    private static final byte MAX_NUM_PINS = 8;
    
    private static final byte VERSION_PROTOCOL_MAJOR = 1;
    private static final byte VERSION_PROTOCOL_MINOR = 1;
    private static final byte VERSION_APPLET_MAJOR = 1;
    private static final byte VERSION_APPLET_MINOR = 3;
    private static final short BUILDID_MAJOR = (short) 0x4472;
    private static final short BUILDID_MINOR = (short) 0x4aa7;
    private static final short ZEROS = 0;

    // * Enable pin size check
    private static final byte PIN_POLICY_SIZE = 1;

    // * Enable pin charset check
    private static final byte PIN_POLICY_CHARSET = 2;

    // * Enable charset mixing check
    private static final byte PIN_POLICY_MIXED = 4;

    // * Numbers are allowed
    private static final byte PIN_CHARSET_NUMBERS = 1;

    // * Upper case letters
    private static final byte PIN_CHARSET_UC_LETTERS = 2;

    // * Lower case letters
    private static final byte PIN_CHARSET_LC_LETTERS = 4;

    // * Punctuation symbols: , .
    private static final byte PIN_CHARSET_PUNCT = 8;

    // * Other binary codes (NUMBERS | OTHERS excludes LETTERS and PUNCT)
    private static final byte PIN_CHARSET_OTHERS = (byte)0x80;

    // * PIN must contain chars from at least 2 different char sets
    private static final byte PIN_MIXED_TWO = 1;

    // * PIN must at least contain chars from both upper and lower case
    private static final byte PIN_MIXED_CASE = 2;

    // * PIN must at least contain 1 char from each char set
    private static final byte PIN_MIXED_ALL = 4;

    /**
     * The User's PIN is pin 0. There is no SO pin.
     */
    private static final byte  USER_IDENTITY    = 0;
    private static final byte  DEFAULT_IDENTITY = 15; // MUSCLE reserved ID
    private static final byte  RA_IDENTITY      = 14; // MUSCLE reserved ID
    private static final short NONCE_SIZE       = (short)8;
    private static final short ISSUER_INFO_SIZE = (short)0xe0;

    private static final short USER_ACL       = (short)(1 << USER_IDENTITY); 
    private static final short DEFAULT_ACL    = (short)(1 << DEFAULT_IDENTITY); 
    private static final short RA_ACL         = (short)(1 << RA_IDENTITY);
    private static final short ANY_ONE_ACL    = (short)0xffff;
    private static final short NO_ONE_ACL     = (short)0;
    
    private static final byte pinPolicies     = 7;
    private static final byte pinMinSize      = 4;
    private static final byte pinMaxSize      = 16;
    
    private static final byte MAX_KEY_TRIES   = 5;
    private static final short IN_OBJECT_CLA  = -1;
    private static final short IN_OBJECT_ID   = -2;
    private static final short OUT_OBJECT_CLA = -1;
    private static final short OUT_OBJECT_ID  = -1;
    private static final byte KEY_ACL_SIZE    = 6;
    
    private static final byte CardEdge_CLA    = (byte)0xB0;
    private static final byte CardManager_CLA = (byte)0x80;
    private static final byte SECURE_CLA      = (byte)0x84;

    /**
     * Instruction codes
     */
    /* Deprecated */
    private static final byte INS_SETUP         = (byte)0x2A;
    private static final byte INS_GEN_KEYPAIR   = (byte)0x30;
    private static final byte INS_EXPORT_KEY    = (byte)0x34;
[...2435 lines suppressed...]

	case INS_CHANGE_PIN:
	    ChangePIN(apdu, buffer);
	    break;

	case INS_CREATE_OBJ:
	    CreateObject(apdu, buffer);
	    break;

	case INS_DELETE_OBJ:
	    DeleteObject(apdu, buffer);
	    break;

	case INS_READ_OBJ:
	    ReadObject(apdu, buffer);
	    break;

	case INS_WRITE_OBJ:
	    WriteObject(apdu, buffer);
	    break;

	case INS_LOGOUT:
	    Logout(apdu,buffer);
	    break;

	case INS_LIST_PINS:
	    ListPINs(apdu, buffer);
	    break;

	case INS_LIST_OBJECTS:
	    ListObjects(apdu, buffer);
	    break;

	case INS_LIST_KEYS:
	    ListKeys(apdu, buffer);
	    break;

	case INS_GET_STATUS:
	    GetStatus(apdu, buffer);
	    break;

	case INS_GET_ISSUER_INFO:
	    getIssuerInfo(apdu, buffer);
	    break;

	case INS_GET_RANDOM:
	    getRandom(apdu, buffer);
	    break;

	case INS_SEED_RANDOM:
	    seedRandom(apdu, buffer);
	    break;

	case INS_GET_LIFECYCLE:
	    getLifeCycle(apdu, buffer);
	    break;

	case INS_GET_BUILDID:
	    getBuildID(apdu, buffer);
	    break;

        case INS_GET_BUILTIN_ACL:
	    getBuiltInACL(apdu, buffer);
	    break;


	case INS_NOP:
	    break;

//      case INS_SETUP:
//      case INS_GEN_KEYPAIR:
//      case INS_EXPORT_KEY:
//      case INS_LOGOUT_ALL:
//      case INS_GET_CHALLENGE:
//      case INS_CAC_EXT_AUTH:
//      case INS_UNBLOCK_PIN:
	default:
	    ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
	    break;
	}
    }

    //
    // handle non-secure standard commands. Called from process.
    //
    private void processSecureAPDU(APDU apdu, byte buffer[])
    {
	byte ins = buffer[ISO7816.OFFSET_INS];

	if (ins != INS_SEC_EXT_AUTH) {
	    verifySecureChannel(apdu, buffer);
	}

	switch (ins) {
	case INS_SEC_EXT_AUTH:
	    externalAuthenticate(apdu, buffer);
	    break;

	case INS_SEC_SET_PIN:
	    resetPIN(apdu, buffer);
	    break;

	case INS_SEC_START_ENROLLMENT:
	    startEnrollment(apdu, buffer);
	    break;
 
	case INS_SEC_IMPORT_KEY_ENCRYPTED:
	    importKeyEncrypted(apdu, buffer);
	    break;

	case INS_SEC_READ_IOBUF:
	    readIOBuf(apdu, buffer);
	    break;

	case INS_SEC_SET_LIFECYCLE:
	    setLifeCycle(apdu, buffer);
	    break;

	case INS_SEC_SET_ISSUER_INFO:
	    setIssuerInfo(apdu, buffer);
	    break;

	case INS_CREATE_OBJ:
	    CreateObject(apdu, buffer);
	    break;

	case INS_WRITE_OBJ:
	    WriteObject(apdu, buffer);
	    break;

	case INS_IMPORT_KEY:
	    ImportKey(apdu, buffer);
	    break;

	case INS_COMPUTE_CRYPT:
	    ComputeCrypt(apdu, buffer);
	    break;

	case INS_CREATE_PIN:
	    CreatePIN(apdu, buffer);
	    break;

	case INS_DELETE_OBJ:
	    DeleteObject(apdu, buffer);
	    break;

	case INS_READ_OBJ:
	    ReadObject(apdu, buffer);
	    break;

        case INS_SEC_SET_BUILTIN_ACL:
	    setBuiltInACL(apdu, buffer);
	    break;

	default:
	    ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
	}
    }

    //
    // **** Most processing starts here!!
    //
    public void process(APDU apdu)
    {
	if (selectingApplet())
	    ISOException.throwIt(ISO7816.SW_NO_ERROR);

	if (!transientInit) {
	    initTransient();
	}

	if ( !cardResetProcessed[0] ) {
	     processCardReset();
	}

	authenticated_id = 0;

	byte buffer[] = apdu.getBuffer();
	byte cla = buffer[ISO7816.OFFSET_CLA];

	switch (cla) {
	case ISO7816.CLA_ISO7816:
	case ISO7816.INS_SELECT:  // right value, but right define?
	    return;
	case CardEdge_CLA:
	    processCardEdgeAPDU(apdu,buffer);
	    break;
	case CardManager_CLA:
	    initializeUpdate(apdu, buffer);
	    break;
	case SECURE_CLA:
	    processSecureAPDU(apdu,buffer);
	    break;
	default:
	    ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
	}
    
    }
}



--- NEW FILE MemoryManager.java ---
//  MUSCLE SmartCard Development
//      Authors:          Tommaso Cucinotta <cucinotta at sssup.it>
//                        David Corcoran    <corcoran at linuxnet.com>
//                        Ludovic Rousseau  <ludovic.rousseau at free.fr>
//                        Jamie Nicolson    <nicolson at netscape.com>
//      Package:          CardEdgeApplet
//      Description:      CardEdge implementation with JavaCard
//      Protocol Authors: Tommaso Cucinotta <cucinotta at sssup.it>
//                        David Corcoran <corcoran at linuxnet.com>
//      Modified:
//                        Eirik Herskedal <ehersked at cs.purdue.edu>
//
// BEGIN LICENSE BLOCK
// Copyright (c) 1999-2002 David Corcoran <corcoran at linuxnet.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// Changes to this license can be made only by the copyright author with
// explicit written consent.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Alternatively, the contents of this file may be used under the terms of
// the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
// case the provisions of the LGPL are applicable instead of those above. If
// you wish to allow use of your version of this file only under the terms
// of the LGPL, and not to allow others to use your version of this file
// under the terms of the BSD license, indicate your decision by deleting
// the provisions above and replace them with the notice and other
// provisions required by the LGPL. If you do not delete the provisions
// above, a recipient may use your version of this file under the terms of
// either the BSD license or the LGPL.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
// END LICENSE_BLOCK

package com.redhat.nkey.applet;

import javacard.framework.Util;

/**
 * Memory Manager class.
 *
 * <p>An instance of this class is capable of handling allocation and
 * deallocation of chunks in a large Java byte array that is allocated
 * once during the object instantiation.</p>
 *
 * <p>The Memory Manager allocates or frees memory chunks in the
 * preallocated byte array on demand.</p>
 *
 * <p>No defragmentation is done, actually.</p>
 *
 * <p>Consecutive freed memory chunks are recompacted.</p>
 *
 * <p>Every allocation takes 2 more bytes to store the allocated block
 * size, just before the allocated offset.</p>
 *
 * <p>A free memory block starts with a node (NODE_SIZE bytes):</p>
 *
 * <pre>
 *   short size;
 *   short next;
 * </pre>
 *
 * @author Tommaso Cucinotta
 * @author David Corcoran
 * @author Ludovic Rousseau
 * @version 0.9.9
 */
public class MemoryManager
{

	/**
	 * Special offset value used as invalid offset
	 */
	public static final short NULL_OFFSET = -1;
	private static final byte NODE_SIZE = 4;
	private byte ptr[];
	private short free_head;

	/**
	 * Constructor for the MemoryManager class
	 *
	 * @param mem_size Size of the memory are to be allocated
	 */
	public MemoryManager(short mem_size)
	{
		ptr = null;
		free_head = NULL_OFFSET;
		Init(mem_size);
	}

	private void Init(short mem_size)
	{
		if(ptr != null)
		{
			return;
		} else
		{
			ptr = new byte[mem_size];
			Util.setShort(ptr, (short)0, mem_size);
			Util.setShort(ptr, (short)2, (short)NULL_OFFSET);
			free_head = 0;
			return;
		}
	}

	/**
	 * Allocate memory
	 *
	 * Each allocation takes actually a 2 bytes overhead.
	 *
	 * @param size Size of the memory block
	 * @return The offset at which allocated memory starts or
	 * NULL_OFFSET if an error occurred.
	 * @see #alloc(short)
	 * @see #freemem()
	 */
	public short alloc(short size)
	{
		short offset = free_head;
		short prev = NULL_OFFSET;
		size += 2;
		if(size < NODE_SIZE)
			size = NODE_SIZE;
		short next_offset;
		for(; offset != NULL_OFFSET; offset = next_offset)
		{
			short free_size = Util.getShort(ptr, offset);
			next_offset = Util.getShort(ptr, (short)(offset + 2));
			if(free_size >= size)
			{
				short remain = (short)(free_size - size);
				if(remain >= NODE_SIZE)
				{
					Util.setShort(ptr, offset, remain);
				} else
				{
					size = free_size;
					remain = 0;
					if(prev == NULL_OFFSET)
						free_head = next_offset;
					else
						Util.setShort(ptr, (short)(prev + 2), next_offset);
				}
				Util.setShort(ptr, (short)(offset + remain), size);
				return (short)(offset + remain + 2);
			}
			prev = offset;
		}

		return NULL_OFFSET;
	}

	/**
	 * Free a memory block
	 *
	 * <p>Consecutive free blocks are recompacted. Recompaction happens on
	 * free(). 4 cases are considered: don't recompact, recompact with
	 * next only, with previous only and with both of them.</p>
	 *
	 * @param offset The offset at which the memory block starts; it was
	 * returned from a previous call to {@link #alloc(short)}
	 *
	 * @see #alloc(short)
	 * @see #freemem()
	 */
	public void free(short offset)
	{
		offset -= 2;
		short size = Util.getShort(ptr, offset);
		short prev = NULL_OFFSET;
		short base = free_head;
		boolean found = false;
		short node_next = 0;
		for(; base != NULL_OFFSET; base = node_next)
		{
			node_next = Util.getShort(ptr, (short)(base + 2));
			if(offset < base)
			{
				found = true;
				break;
			}
			prev = base;
		}

		if(found && (short)(offset + size) == base)
		{
			size += Util.getShort(ptr, base);
			Util.setShort(ptr, offset, size);
			if(prev != NULL_OFFSET)
				Util.setShort(ptr, (short)(prev + 2), node_next);
			else
				free_head = node_next;
			base = node_next;
		}
		if(prev != NULL_OFFSET)
		{
			short prev_size = Util.getShort(ptr, prev);
			if((short)(prev + prev_size) == offset)
			{
				Util.setShort(ptr, prev, (short)(prev_size + size));
			} else
			{
				Util.setShort(ptr, (short)(offset + 2), base);
				Util.setShort(ptr, (short)(prev + 2), offset);
			}
		} else
		{
			Util.setShort(ptr, (short)(offset + 2), base);
			free_head = offset;
		}
	}

	/**
	 * Get available free memory
	 *
	 * @return The total amount of available free memory, equal to the
	 * sum of all free fragments' sizes.
	 *
	 * @see #free(short)
	 * @see #alloc(short)
	 */
	public short freemem()
	{
		short offset = free_head;
		short total = 0;
		for(; offset != NULL_OFFSET; offset = Util.getShort(ptr, (short)(offset + 2)))
			total = (short)((total + Util.getShort(ptr, offset)) - 2);

		return total;
	}

	/**
	 * Get the size of a memory block
	 *
	 * @param offset The offset at which the memory block starts
	 */
	public short getBlockSize(short offset)
	{
		return (short)(Util.getShort(ptr, (short)(offset - 2)) - 2);
	}

	/**
	 * Retrieve the Java byte array containing all the memory contents.
	 *
	 * <p>To optimize, we don't use external buffers, but we directly
	 * copy from the memory array.</p>
	 *
	 * <p><b>Use this function only if really required.</b></p>
	 *
	 * @return The Java byte array containing all memory contents
	 */
	public byte[] getBuffer()
	{
		return ptr;
	}

	/**
	 * Read a byte value from memory
	 *
	 * @param base The complete memory location (offset) of the byte to
	 * read
	 * @return The byte value
	 */
	public byte getByte(short base)
	{
		return ptr[base];
	}

	/**
	 * Read a byte value from memory
	 *
	 * @param base The base memory location (offset) of the byte to read
	 * @param offset The offset of the byte (is added to the base
	 * parameter)
	 * @return The byte value
	 */
	public byte getByte(short base, short offset)
	{
		return ptr[(short)(base + offset)];
	}

	/**
	 * Copy a byte sequence from memory
	 *
	 * @param dst_bytes[] The destination byte array
	 * @param dst_offset The offset at which the sequence will be copied
	 * in dst_bytes[]
	 * @param src_base The base memory location (offset) of the source
	 * byte sequence
	 * @param src_offset The offset of the source byte sequence (is
	 * added to the src_base parameter)
	 * @param size The number of bytes to be copied
	 */
	public void getBytes(byte dst_bytes[], short dst_offset, short src_base, 
	                     short src_offset, short size)
	{
		Util.arrayCopy(ptr, (short)(src_base + src_offset), 
		               dst_bytes, dst_offset, size);
	}

	/**
	 * Gets the size of the greatest chunk of available memory
	 *
	 * @return The size of the greatest free memory chunk, or zero if
	 * there is no free mem left
	 */
	public short getMaxSize()
	{
		short max_size = 2;
		for(short base = free_head; base != NULL_OFFSET; 
		    base = Util.getShort(ptr, (short)(base + 2)))
		{
			short size = Util.getShort(ptr, base);
			if(size > max_size)
				max_size = size;
		}

		return (short)(max_size - 2);
	}

	/**
	 * Read a short value from memory
	 *
	 * @param base The base memory location (offset) of the short to
	 * read
	 * @return The short value
	 */
	public short getShort(short base)
	{
		return Util.getShort(ptr, base);
	}

	/**
	 * Read a short value from memory
	 *
	 * @param base The base memory location (offset) of the short to
	 * read
	 * @param offset The offset of the short (is added to the base
	 * parameter)
	 * @return The short value
	 */
	public short getShort(short base, short offset)
	{
		return Util.getShort(ptr, (short)(base + offset));
	}

	/**
	 * Resize (only clamping is supported) a previously allocated memory
	 * chunk
	 *
	 * @param offset Memory offset as returned by alloc()
	 * @param new_size ew size of the memory block
	 * @return True if it was possible to realloc(), False otherwise
	 *
	 * @see #alloc(short)
	 * @see #free(short)
	 * @see #freemem()
	 */
	public boolean realloc(short offset, short new_size)
	{
		short actual_size = Util.getShort(ptr, (short)(offset - 2));
		new_size += 2;
		if(new_size < 3 || (short)(actual_size - new_size) < NODE_SIZE)
		{
			return false;
		} else
		{
			Util.setShort(ptr, (short)(offset - 2), new_size);
			Util.setShort(ptr, (short)((offset + new_size) - 2), (short)(actual_size - new_size));
			free((short)(offset + new_size));
			return true;
		}
	}

	/**
	 * Set a byte value into memory
	 *
	 * @param base The complete memory location (offset) of the byte to
	 * set
	 * @param b The new byte value
	 */
	public void setByte(short base, byte b)
	{
		ptr[base] = b;
	}

	/**
	 * Set a byte value into memory
	 *
	 * @param base The base memory location (offset) of the byte to set
	 * @param offset The offset of the byte (is added to the base
	 * parameter)
	 * @param b The new byte value
	 */
	public void setByte(short base, short offset, byte b)
	{
		ptr[(short)(base + offset)] = b;
	}

	/**
	 * Copy a byte sequence into memory
	 *
	 * @param dst_base The base memory location (offset) of the
	 * destination byte sequence
	 * @param dst_offset The offset of the destination byte sequence (is
	 * added to the dst_base parameter)
	 * @param src_bytes[] The source byte array
	 * @param src_offset The offset at which the source sequence starts
	 * in src_bytes[]
	 * @param size The number of bytes to be copied
	 */
	public void setBytes(short dst_base, short dst_offset, byte src_bytes[], short src_offset, short size)
	{
		Util.arrayCopy(src_bytes, src_offset, ptr, (short)(dst_base + dst_offset), size);
	}

	/**
	 * Set a short value into memory
	 *
	 * @param base The complete memory location (offset) of the short to
	 * set
	 * @param b The short value
	 */
	public void setShort(short base, short b)
	{
		Util.setShort(ptr, base, b);
	}

	/**
	 * Set a short value into memory
	 */
	public void setShort(short base, short offset, short b)
	{
		Util.setShort(ptr, (short)(base + offset), b);
	}
}



--- NEW FILE ObjectManager.java ---
//  MUSCLE SmartCard Development
//      Authors:          Tommaso Cucinotta <cucinotta at sssup.it>
//                        David Corcoran    <corcoran at linuxnet.com>
//                        Ludovic Rousseau  <ludovic.rousseau at free.fr>
//                        Jamie Nicolson    <nicolson at netscape.com>
//      Package:          CardEdgeApplet
//      Description:      CardEdge implementation with JavaCard
//      Protocol Authors: Tommaso Cucinotta <cucinotta at sssup.it>
//                        David Corcoran <corcoran at linuxnet.com>
//      Modified:
//                        Eirik Herskedal <ehersked at cs.purdue.edu>
//
// BEGIN LICENSE BLOCK
// Copyright (C) 1999-2002 David Corcoran <corcoran at linuxnet.com>
// Copyright (C) 2006 Red Hat, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// Changes to this license can be made only by the copyright author with
// explicit written consent.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Alternatively, the contents of this file may be used under the terms of
// the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
// case the provisions of the LGPL are applicable instead of those above. If
// you wish to allow use of your version of this file only under the terms
// of the LGPL, and not to allow others to use your version of this file
// under the terms of the BSD license, indicate your decision by deleting
// the provisions above and replace them with the notice and other
// provisions required by the LGPL. If you do not delete the provisions
// above, a recipient may use your version of this file under the terms of
// either the BSD license or the LGPL.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
// END LICENSE_BLOCK

package com.redhat.nkey.applet;

import javacard.framework.ISOException;
import javacard.framework.Util;

// Referenced classes of package com.redhat.nkey.applet:
//			MemoryManager

/**
 * Object Manager Class
 *
 * <p>Objects are linked in a list in the dynamic memory. No smart search
 * is done at the moment.</p>
 *
 * <p>TODO - Could we definitively avoid a map enforcing the ID (equal to
 * the memory address, i.e.) - security implications ?</p>
 *
 * Object fields:
 * <pre>
 *    short next
 *    short obj_class
 *    short obj_id
 *    short obj_size
 *    byte[] data
 * </pre>
 *
 * @author Tommaso Cucinotta
 * @author David Corcoran
 * @author Ludovic Rousseau
 * @version 0.9.9
 *
 */
public class ObjectManager
{
	public static final byte OBJ_ACL_SIZE = 6;

	private static final byte OBJ_HEADER_SIZE = 14;
	private static final byte OBJ_H_NEXT = 0;
	private static final byte OBJ_H_CLASS = 2;
	private static final byte OBJ_H_ID = 4;
	private static final byte OBJ_H_ACL = 6;
	private static final short OBJ_ACL_READ   =  6;
	private static final short OBJ_ACL_WRITE  =  8;
	private static final short OBJ_ACL_DELETE = 10;
	private static final byte OBJ_H_SIZE = 12;
	private static final byte OBJ_H_DATA = 14;

	/**
	 * There have been memory problems on the card
	 */
	public static final short SW_NO_MEMORY_LEFT   = (short)0x9C01;
	public static final short SW_OBJECT_NOT_FOUND = (short)0x9C07;
	public static final short SW_OBJECT_EXISTS    = (short)0x9C08;

	/**
	 * Size of an Object Record filled by getFirstRecord() or
	 * getNextRecord(): ID, Size, ACL
	 */
	public static final short RECORD_SIZE = 14;

	/**
	 * Iterator on objects.
	 */
	private short it;

	/**
	 * The Memory Manager object
	 */
	private MemoryManager mem;

	/**
	 * Head of the objects' list
	 */
	private short obj_list_head;

	/**
	 * Constructor for the ObjectManager class.
	 *
	 * @param mem_ref The MemoryManager object to be used to allocate
	 * objects' memory.
	 */
	public ObjectManager(MemoryManager mem_ref)
	{
		mem = null;
		obj_list_head = -1;
		mem = mem_ref;
		obj_list_head = -1;
	}

	/**
	 * Check if logged in identities satisfy requirements for an
	 * operation
	 *
	 * @param required_ids The required identities as from an ACL short
	 * @param logged_ids The current logged in identities as stored in
	 * CardEdge.logged_ids
	 */
	private boolean authorizeOp(short base, short logged_ids, short offset)
	{
		short required_ids = mem.getShort((short)(base - OBJ_H_DATA), offset);
		return (required_ids & logged_ids) != 0;
	}

	/**
	 * Allow or unallow delete on object given the logged identities
	 */
	public boolean authorizeDeleteFromAddress(short base, short logged_ids)
	{
		return authorizeOp(base, logged_ids, OBJ_ACL_DELETE);
	}

	/**
	 * Allow or unallow read on object given the logged identities
	 *
	 * @param base The object base address as returned from
	 * getBaseAddress()
	 * @param logged_ids The current logged in identities as stored in
	 * CardEdge.logged_ids
	 */
	public boolean authorizeReadFromAddress(short base, short logged_ids)
	{
		return authorizeOp(base, logged_ids, OBJ_ACL_READ);
	}

	/**
	 * Allow or unallow write on object given the logged identities
	 *
	 * @param base The object base address as returned from
	 * getBaseAddress()
	 * @param logged_ids The current logged in identities as stored in
	 * CardEdge.logged_ids
	 */
	public boolean authorizeWriteFromAddress(short base, short logged_ids)
	{
		return authorizeOp(base, logged_ids, OBJ_ACL_WRITE);
	}

	/**
	 * Clamps an object freeing the unused memory
	 *
	 * @throws SW_NO_MEMORY_LEFT exception if cannot allocate the
	 * memory. Does not check if object exists.
	 *
	 * @param type Object Type
	 * @param id Object ID (Type and ID form a generic 4 bytes
	 * identifier)
	 * @param new_size The new object size (must be less than current
	 * size)
	 *
	 * @return True if clamp was possible, false otherwise
	 */
	public boolean clampObject(short type, short id, short new_size)
	{
		short base = getEntry(type, id);
		if(base == -1)
			ISOException.throwIt((short)SW_OBJECT_NOT_FOUND);
		if(mem.realloc(base, (short)(new_size + RECORD_SIZE)))
		{
			mem.setShort(base, (short)OBJ_H_SIZE, new_size);
			return true;
		} else
		{
			return false;
		}
	}

	/**
	 * Compare an object's ACL with the provided ACL.
	 *
	 * @param base The object base address, as returned from
	 * getBaseAddress()
	 * @param acl The buffer containing the ACL
	 *
	 * @return True if the ACLs are equal
	 */
	public boolean compareACLFromAddress(short base, byte acl[])
	{
		return Util.arrayCompare(mem.getBuffer(), 
			(short)((base - OBJ_HEADER_SIZE) + OBJ_H_ACL), acl, 
			(short)0, (short)OBJ_ACL_SIZE) == 0;
	}

	/**
	 * Creates an object with specified parameters.
	 *
	 * @throws SW_NO_MEMORY_LEFT exception if cannot allocate the
	 * memory. Does not check if object exists.
	 *
	 * @param type Object Type
	 * @param id Object ID (Type and ID form a generic 4 bytes
	 * identifier)
	 * @param acl_buf Java byte array containing the ACL for the new object
	 * @param acl_offset Offset at which the ACL starts in acl_buf[]
	 *
	 * @return The memory base address for the object. It can be used in
	 * successive calls to xxxFromAddress() methods.
	 *
	 */
	public short createObject(short type, short id, short size, 
	                          byte acl_buf[], short acl_offset)
	{
		if (exists(type, id))
			ISOException.throwIt(SW_OBJECT_EXISTS);
		short base = mem.alloc((short)(size + OBJ_HEADER_SIZE));
		if(base == -1)
			ISOException.throwIt((short)SW_NO_MEMORY_LEFT);
		mem.setShort(base, (short)OBJ_H_NEXT,  obj_list_head);
		mem.setShort(base, (short)OBJ_H_CLASS, type);
		mem.setShort(base, (short)OBJ_H_ID,    id);
		mem.setShort(base, (short)OBJ_H_SIZE,  size);
		mem.setBytes(base, (short)OBJ_H_ACL, acl_buf, acl_offset, 
		             (short)OBJ_ACL_SIZE);
		obj_list_head = base;
		return (short)(base + OBJ_H_DATA);
	}

	/**
	 * Creates an object with the maximum available size
	 */
	public short createObjectMax(short type, short id, 
	                             byte acl_buf[], short acl_offset)
	{
		short obj_size = mem.getMaxSize();
		if(obj_size == 0)
			ISOException.throwIt((short)SW_NO_MEMORY_LEFT);
		return createObject(type, id, (short)(obj_size - OBJ_H_DATA), 
		                    acl_buf, acl_offset);
	}

	/**
	 * Destroy the specified object
	 *
	 * @param type Object Type
	 * @param id Object ID (Type and ID form a generic 4 bytes
	 * identifier)
	 * @param secure If true, object memory is zeroed before being
	 * released.
	 */
	public void destroyObject(short type, short id, boolean secure)
	{
		boolean found;
		do {
			short curr = obj_list_head;
			short prev = -1;

			for (found = false; !found && curr != -1; ) {
				if(mem.getShort(curr, (short)OBJ_H_CLASS) == type && 
				   mem.getShort(curr, (short)OBJ_H_ID)    == id) {
					found = true;
				} else {
					prev = curr;
					curr = mem.getShort(curr, (short)0);
				}
			}
			if(found) {
				if(prev != -1)
					mem.setShort(prev, (short)0, mem.getShort(curr, (short)0));
				else
					obj_list_head = mem.getShort(curr, (short)0);
				if(secure) {
					Util.arrayFillNonAtomic(mem.getBuffer(), 
						(short)(curr + OBJ_H_DATA), 
						mem.getShort(curr, (short)OBJ_H_SIZE), 
						(byte)0);
				}
				mem.free(curr);
			}
		} while (found);
	}

	/**
	 * Checks if an object exists
	 *
	 * @param type The object type
	 * @param id The object ID
	 *
	 * @return true if object exists
	 */
	public boolean exists(short type, short id)
	{
		short base = getEntry(type, id);
		return base != -1;
	}

	/**
	 * Returns the data base address (offset) for an object.
	 *
	 * <p>The base address can be used for further calls to
	 * xxxFromAddress() methods</p>
	 *
	 * <p>This function should only be used if performance issue arise.
	 * setObjectData() and getObjectData() should be used, instead.</p>
	 *
	 * @param type Object Type
	 * @param id Object ID (Type and ID form a generic 4 bytes
	 * identifier)
	 *
	 * @return The starting offset of the object. At this location
	 */
	public short getBaseAddress(short type, short id)
	{
		short base = getEntry(type, id);
		if(base == -1)
			return -1;
		else
			return (short)(base + OBJ_H_DATA);
	}

	/**
	 * Returns the header base address (offset) for the specified
	 * object.
	 *
	 * <p>Object header is found at the returned offset, while object
	 * data starts right after the header.</p>
	 *
	 * <p>This performs a linear search, so performance issues could
	 * arise as the number of objects grows If object is not found,
	 * then returns NULL_OFFSET.</p>
	 *
	 * @param type Object Type
	 * @param id Object ID (Type and ID form a generic 4 bytes
	 * identifier)
	 *
	 * @return The starting offset of the object or NULL_OFFSET if the
	 * object is not found.
	 */
	private short getEntry(short type, short id)
	{
		for(short base = obj_list_head; base != -1; 
		    base = mem.getShort(base, (short)0)) {
			if(mem.getShort(base, (short)OBJ_H_CLASS) == type && 
			   mem.getShort(base, (short)OBJ_H_ID) == id)
				return base;
		}
		return -1;
	}

	/**
	 * Resets the objects iterator and retrieves the information record
	 * of the first object, if any.
	 *
	 * @param buffer The byte array into which the record will be copied
	 * @param offset The offset in buffer[] at which the record will be
	 * copied
	 *
	 * @return True if an object was found. False if there are no
	 * objects.
	 *
	 * @see #getNextRecord(byte[], short)
	 */
	public boolean getFirstRecord(byte buffer[], short offset)
	{
		it = obj_list_head;
		return getNextRecord(buffer, offset);
	}

	/**
	 * Retrieves the information record of the next object, if any.
	 *
	 * @param buffer The byte array into which the record will be copied
	 * @param offset The offset in buffer[] at which the record will be
	 * copied
	 *
	 * @return True if an object was found. False if there are no more
	 * objects to inspect.
	 *
	 * @see #getFirstRecord(byte[], short)
	 */
	public boolean getNextRecord(byte buffer[], short offset)
	{
		if(it == -1)
		{
			return false;
		} else
		{
			Util.setShort(buffer, offset, mem.getShort(it, (short)2));
			Util.setShort(buffer, (short)(offset + 2), 
					mem.getShort(it, (short)OBJ_H_ID));
			Util.setShort(buffer, (short)(offset + 4), (short)0);
			Util.setShort(buffer, (short)(offset + 6), 
					mem.getShort(it, (short)OBJ_H_SIZE));
			Util.arrayCopyNonAtomic(mem.getBuffer(), 
					(short)(it + OBJ_H_ACL), buffer, 
					(short)(offset + 8), 
					(short)OBJ_ACL_SIZE);
			it = mem.getShort(it, (short)0);
			return true;
		}
	}

	/**
	 * Returns object size from the base address
	 */
	public short getSizeFromAddress(short base)
	{
		return mem.getShort((short)((base - OBJ_H_DATA) + OBJ_H_SIZE));
	}

	/**
	 * Set the object's ACL.
	 */
	private void setACL(short type, short id, byte acl_buf[], short acl_offset)
	{
		short base = getEntry(type, id);
		mem.setBytes(base, (short)OBJ_H_ACL, acl_buf, acl_offset, (short)OBJ_ACL_SIZE);
	}
}





More information about the Fedora-directory-commits mailing list