// Copyright (c) 2002 Graz University of Technology. 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 end-user documentation included with the redistribution, if any, must // include the following acknowledgment: // // "This product includes software developed by IAIK of Graz University of // Technology." // // Alternately, this acknowledgment may appear in the software itself, if and // wherever such third-party acknowledgments normally appear. // // 4. The names "Graz University of Technology" and "IAIK of Graz University of // Technology" must not be used to endorse or promote products derived from this // software without prior written permission. // // 5. Products derived from this software may not be called "IAIK PKCS Wrapper", // nor may "IAIK" appear in their name, without prior written permission of // Graz University of Technology. // // THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 LICENSOR 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. package iaik.pkcs.pkcs11; import iaik.pkcs.pkcs11.wrapper.CK_TOKEN_INFO; import iaik.pkcs.pkcs11.wrapper.Constants; import iaik.pkcs.pkcs11.wrapper.PKCS11Constants; import java.util.Date; /** * Objects of this class provide information about a token. Serial number, * manufacturer, free memory,... . Notice that this is just a snapshot of the * token's status at the time this object was created. * * @author Karl Scheibelhofer * @version 1.0 * @invariants (label_ <> null) * and (manufacturerID_ <> null) * and (model_ <> null) * and (serialNumber_ <> null) * and (hardwareVersion_ <> null) * and (firmwareVersion_ <> null) * and (time_ <> null) */ public class TokenInfo implements Cloneable { /** * This is the value which can be used for ulMaxSessionCount and * ulMaxRwSessionCount to express an infinite number. */ public static final long EFFECTIVELY_INFINITE = PKCS11Constants.CK_EFFECTIVELY_INFINITE; /** * This is the value which can be used for ulMaxSessionCount, ulSessionCount, * ulMaxRwSessionCount, ulRwSessionCount, ulTotalPublicMemory, * ulFreePublicMemory, ulTotalPrivateMemory, and ulFreePrivateMemory to signal * that the information is unavailable. */ public static final long UNAVAILABLE_INFORMATION = PKCS11Constants.CK_UNAVAILABLE_INFORMATION; /** * The label of this token. */ protected String label_; /** * The identifier of the manufacturer of this token. */ protected String manufacturerID_; /** * The model of this token. */ protected String model_; /** * The serial number of this token. */ protected String serialNumber_; /** * The maximum number of concurrent (open) sessions. */ protected long maxSessionCount_; /** * The current number of open sessions. */ protected long sessionCount_; /** * Maximum number of concurrent (open) read-write sessions. */ protected long maxRwSessionCount_; /** * The current number of open read-write sessions. */ protected long rwSessionCount_; /** * The maximum PIN length that this token allows. */ protected long maxPinLen_; /** * The minimum PIN length that this token allows. */ protected long minPinLen_; /** * The total amount of memory for public objects on this token. */ protected long totalPublicMemory_; /** * The amount of free memory for public objects on this token. */ protected long freePublicMemory_; /** * The total amount of memory for private objects on this token. */ protected long totalPrivateMemory_; /** * The amount of free memory for private objects on this token. */ protected long freePrivateMemory_; /** * The version of the hardware of this token. */ protected Version hardwareVersion_; /** * The version of the firmware of this token. */ protected Version firmwareVersion_; /** * The current time on the token. This value only makes sense, if the token * contains a clock. */ protected Date time_; /** * True, if the token has a random numebr generator. */ protected boolean rng_; /** * True, if the token is write protected. */ protected boolean writeProtected_; /** * True, if the token requires the user to login to perform certain * operations. */ protected boolean loginRequired_; /** * True, if the user-PIN is already initialized. */ protected boolean userPinInitialized_; /** * True, if a successful save of a session’s cryptographic operations state * always contains all keys needed to restore the state of the session. */ protected boolean restoreKeyNotNeeded_; /** * True, if the token has a clock. */ protected boolean clockOnToken_; /** * True, if there are different means to authenticate the user than passing * the user-PIN to a login operation. */ protected boolean protectedAuthenticationPath_; /** * True, if the token supports dual crypto operations. */ protected boolean dualCryptoOperations_; /** * True, if the token is already initialized. */ protected boolean tokenInitialized_; /** * True, if the token supports secondary authentication for private key * objects. */ protected boolean secondaryAuthentication_; /** * True, if the user-PIN has been entered incorrectly at least once since the * last successful authentication. */ protected boolean userPinCountLow_; /** * True, if the user has just one try left to supply the correct PIN before * the user-PIN gets locked. */ protected boolean userPinFinalTry_; /** * True, if the user-PIN is locked. */ protected boolean userPinLocked_; /** * True, if the user PIN value is the default value set by token initialization * or manufacturing. */ protected boolean userPinToBeChanged_; /** * True, if the security officer-PIN has been entered incorrectly at least * once since the last successful authentication. */ protected boolean soPinCountLow_; /** * True, if the security officer has just one try left to supply the correct * PIN before the security officer-PIN gets locked. */ protected boolean soPinFinalTry_; /** * True, if the security officer-PIN is locked. */ protected boolean soPinLocked_; /** * True, if the security officer-PIN value is the default value set by token * initialization or manufacturing. */ protected boolean soPinToBeChanged_; /** * Constructor taking CK_TOKEN_INFO as given returned by * PKCS11.C_GetTokenInfo. * * @param ckTokenInfo The CK_TOKEN_INFO object as returned by * PKCS11.C_GetTokenInfo. * @preconditions (ckTokenInfo <> null) * @postconditions */ protected TokenInfo(CK_TOKEN_INFO ckTokenInfo) { if (ckTokenInfo == null) { throw new NullPointerException("Argument \"ckTokenInfo\" must not be null."); } label_ = new String(ckTokenInfo.label); manufacturerID_ = new String(ckTokenInfo.manufacturerID); model_ = new String(ckTokenInfo.model); serialNumber_ = new String(ckTokenInfo.serialNumber); maxSessionCount_ = ckTokenInfo.ulMaxSessionCount; sessionCount_ = ckTokenInfo.ulSessionCount; maxRwSessionCount_ = ckTokenInfo.ulMaxRwSessionCount; rwSessionCount_ = ckTokenInfo.ulRwSessionCount; maxPinLen_ = ckTokenInfo.ulMaxPinLen; minPinLen_ = ckTokenInfo.ulMinPinLen; totalPublicMemory_ = ckTokenInfo.ulTotalPublicMemory; freePublicMemory_ = ckTokenInfo.ulFreePublicMemory; totalPrivateMemory_ = ckTokenInfo.ulTotalPrivateMemory; freePrivateMemory_ = ckTokenInfo.ulFreePrivateMemory; hardwareVersion_ = new Version(ckTokenInfo.hardwareVersion); firmwareVersion_ = new Version(ckTokenInfo.firmwareVersion); time_ = Util.parseTime(ckTokenInfo.utcTime); rng_ = (ckTokenInfo.flags & PKCS11Constants.CKF_RNG) != 0L; writeProtected_ = (ckTokenInfo.flags & PKCS11Constants.CKF_WRITE_PROTECTED) != 0L; loginRequired_ = (ckTokenInfo.flags & PKCS11Constants.CKF_LOGIN_REQUIRED) != 0L; userPinInitialized_ = (ckTokenInfo.flags & PKCS11Constants.CKF_USER_PIN_INITIALIZED) != 0L; restoreKeyNotNeeded_ = (ckTokenInfo.flags & PKCS11Constants.CKF_RESTORE_KEY_NOT_NEEDED) != 0L; clockOnToken_ = (ckTokenInfo.flags & PKCS11Constants.CKF_CLOCK_ON_TOKEN) != 0L; protectedAuthenticationPath_ = (ckTokenInfo.flags & PKCS11Constants.CKF_PROTECTED_AUTHENTICATION_PATH) != 0L; dualCryptoOperations_ = (ckTokenInfo.flags & PKCS11Constants.CKF_DUAL_CRYPTO_OPERATIONS) != 0L; tokenInitialized_ = (ckTokenInfo.flags & PKCS11Constants.CKF_TOKEN_INITIALIZED) != 0L; secondaryAuthentication_ = (ckTokenInfo.flags & PKCS11Constants.CKF_SECONDARY_AUTHENTICATION) != 0L; userPinCountLow_ = (ckTokenInfo.flags & PKCS11Constants.CKF_USER_PIN_COUNT_LOW) != 0L; userPinFinalTry_ = (ckTokenInfo.flags & PKCS11Constants.CKF_USER_PIN_FINAL_TRY) != 0L; userPinLocked_ = (ckTokenInfo.flags & PKCS11Constants.CKF_USER_PIN_LOCKED) != 0L; userPinToBeChanged_ = (ckTokenInfo.flags & PKCS11Constants.CKF_USER_PIN_TO_BE_CHANGED) != 0L; soPinCountLow_ = (ckTokenInfo.flags & PKCS11Constants.CKF_SO_PIN_COUNT_LOW) != 0L; soPinFinalTry_ = (ckTokenInfo.flags & PKCS11Constants.CKF_SO_PIN_FINAL_TRY) != 0L; soPinLocked_ = (ckTokenInfo.flags & PKCS11Constants.CKF_SO_PIN_LOCKED) != 0L; soPinToBeChanged_ = (ckTokenInfo.flags & PKCS11Constants.CKF_SO_PIN_TO_BE_CHANGED) != 0L; } /** * Create a (deep) clone of this object. * * @return A clone of this object. * @preconditions * @postconditions (result <> null) * and (result instanceof TokenInfo) * and (result.equals(this)) */ public java.lang.Object clone() { TokenInfo clone; try { clone = (TokenInfo) super.clone(); clone.hardwareVersion_ = (Version) this.hardwareVersion_.clone(); clone.firmwareVersion_ = (Version) this.firmwareVersion_.clone(); clone.time_ = new Date(this.time_.getTime()); // clone() unsupported in JDK 1.1 } catch (CloneNotSupportedException ex) { // this must not happen, because this class is cloneable throw new TokenRuntimeException("An unexpected clone exception occurred.", ex); } return clone; } /** * Get the label of this token. * * @return The label of this token. * @preconditions * @postconditions (result <> null) */ public String getLabel() { return label_; } /** * Get the manufacturer identifier. * * @return A string identifying the manufacturer of this token. * @preconditions * @postconditions (result <> null) */ public String getManufacturerID() { return manufacturerID_; } /** * Get the model of this token. * * @return A string specifying the model of this token. * @preconditions * @postconditions (result <> null) */ public String getModel() { return model_; } /** * Get the serial number of this token. * * @return A string holding the serial number of this token. * @preconditions * @postconditions (result <> null) */ public String getSerialNumber() { return serialNumber_; } /** * Get the maximum allowed number of (open) concurrent sessions. * * @return The maximum allowed number of (open) concurrent sessions. * @preconditions * @postconditions */ public long getMaxSessionCount() { return maxSessionCount_; } /** * Get the current number of open sessions. * * @return The current number of open sessions. * @preconditions * @postconditions */ public long getSessionCount() { return sessionCount_; } /** * Get the maximum allowed number of (open) concurrent read-write sessions. * * @return The maximum allowed number of (open) concurrent read-write * sessions. * @preconditions * @postconditions */ public long getMaxRwSessionCount() { return maxRwSessionCount_; } /** * Get the current number of open read-write sessions. * * @return The current number of open read-write sessions. * @preconditions * @postconditions */ public long getRwSessionCount() { return rwSessionCount_; } /** * Get the maximum length for the PIN. * * @return The maximum length for the PIN. * @preconditions * @postconditions */ public long getMaxPinLen() { return maxPinLen_; } /** * Get the minimum length for the PIN. * * @return The minimum length for the PIN. * @preconditions * @postconditions */ public long getMinPinLen() { return minPinLen_; } /** * Get the total amount of memory for public objects. * * @return The total amount of memory for public objects. * @preconditions * @postconditions */ public long getTotalPublicMemory() { return totalPublicMemory_; } /** * Get the amount of free memory for public objects. * * @return The amount of free memory for public objects. * @preconditions * @postconditions */ public long getFreePublicMemory() { return freePublicMemory_; } /** * Get the total amount of memory for private objects. * * @return The total amount of memory for private objects. * @preconditions * @postconditions */ public long getTotalPrivateMemory() { return totalPrivateMemory_; } /** * Get the amount of free memory for private objects. * * @return The amount of free memory for private objects. * @preconditions * @postconditions */ public long getFreePrivateMemory() { return freePrivateMemory_; } /** * Get the version of the token's hardware. * * @return The version of the token's hardware. * @preconditions * @postconditions (result <> null) */ public Version getHardwareVersion() { return hardwareVersion_; } /** * Get the version of the token's firmware. * * @return The version of the token's firmware. * @preconditions * @postconditions (result <> null) */ public Version getFirmwareVersion() { return firmwareVersion_; } /** * Get the current time of the token's clock. This value does only make sense * if the token has a clock. Remind that, this is the time this object was * created and not the time the application called this method. * * @return The current time on the token's clock. * @see #isClockOnToken() * @preconditions * @postconditions (result <> null) */ public Date getTime() { return time_; } /** * Check, if the token has a random number generator. * * @return True, if the token has a random number generator. False, otherwise. * @preconditions * @postconditions */ public boolean isRNG() { return rng_; } /** * Check, if the token is write protected. * * @return True, if the token is write protected. False, otherwise. * @preconditions * @postconditions */ public boolean isWriteProtected() { return writeProtected_; } /** * Check, if the token requires the user to log in before certain operations * can be performed. * * @return True, if the token requires the user to log in before certain * operations can be performed. False, otherwise. * @preconditions * @postconditions */ public boolean isLoginRequired() { return loginRequired_; } /** * Check, if the user-PIN is already initialized. * * @return True, if the user-PIN is already initialized. False, otherwise. * @preconditions * @postconditions */ public boolean isUserPinInitialized() { return userPinInitialized_; } /** * Check, if a successful save of a session’s cryptographic operations * state always contains all keys needed to restore the state of the * session. * * @return True, if a successful save of a session’s cryptographic operations * state always contains all keys needed to restore the state of the * session. False, otherwise. * @preconditions * @postconditions */ public boolean isRestoreKeyNotNeeded() { return restoreKeyNotNeeded_; } /** * Check, if the token has an own clock. * * @return True, if the token has its own clock. False, otherwise. * @preconditions * @postconditions */ public boolean isClockOnToken() { return clockOnToken_; } /** * Check, if the token has an protected authentication path. This means that * a user may log in without providing a PIN to the login method, because the * token has other means to authenticate the user; e.g. a PIN-pad on the * reader or some biometric authentication. * * @return True, if the token has an protected authentication path. False, * otherwise. * @preconditions * @postconditions */ public boolean isProtectedAuthenticationPath() { return protectedAuthenticationPath_; } /** * Check, if the token supports dual crypto operations. * * @return True, if the token supports dual crypto operations. False, * otherwise. * @preconditions * @postconditions */ public boolean isDualCryptoOperations() { return dualCryptoOperations_; } /** * Check, if the token is already initialized. * * @return True, if the token is already initialized. False, otherwise. * @preconditions * @postconditions */ public boolean isTokenInitialized() { return tokenInitialized_; } /** * Check, if the token supports secondary authentication for private key * objects. * * @return True, if the token supports secondary authentication. False, * otherwise. * @preconditions * @postconditions */ public boolean isSecondaryAuthentication() { return secondaryAuthentication_; } /** * Check, if the user-PIN has been entered incorrectly at least once since the * last successful authentication. * * @return True, if the the user-PIN has been entered incorrectly at least one * since the last successful authentication. False, otherwise. * @preconditions * @postconditions */ public boolean isUserPinCountLow() { return userPinCountLow_; } /** * Check, if the user has just one try left to supply the correct PIN before * the user-PIN gets locked. * * @return True, if the user has just one try left to supply the correct PIN * before the user-PIN gets locked. False, otherwise. * @preconditions * @postconditions */ public boolean isUserPinFinalTry() { return userPinFinalTry_; } /** * Check, if the user-PIN is locked. * * @return True, if the user-PIN is locked. False, otherwise. * @preconditions * @postconditions */ public boolean isUserPinLocked() { return userPinLocked_; } /** * Check, if the user PIN value is the default value set by token * initialization or manufacturing. * * @return True, if the user PIN value is the default value set by token * initialization or manufacturing. False, otherwise. * @preconditions * @postconditions */ public boolean isUserPinToBeChanged() { return userPinToBeChanged_; } /** * Check, if the security officer-PIN has been entered incorrectly at least * once since the last successful authentication. * * @return True, if the the security officer-PIN has been entered incorrectly * at least one since the last successful authentication. False, * otherwise. * @preconditions * @postconditions */ public boolean isSoPinCountLow() { return soPinCountLow_; } /** * Check, if the security officer has just one try left to supply the correct * PIN before the security officer-PIN gets locked. * * @return True, if the security officer has just one try left to supply the * correct PIN before the security officer-PIN gets locked. False, * otherwise. * @preconditions * @postconditions */ public boolean isSoPinFinalTry() { return soPinFinalTry_; } /** * Check, if the security officer-PIN is locked. * * @return True, if the security officer-PIN is locked. False, otherwise. * @preconditions * @postconditions */ public boolean isSoPinLocked() { return soPinLocked_; } /** * Check, if the security officer PIN value is the default value set by token * initialization or manufacturing. * * @return True, if the security officer PIN value is the default value set by * token initialization or manufacturing. False, otherwise. * @preconditions * @postconditions */ public boolean isSoPinToBeChanged() { return soPinToBeChanged_; } /** * Returns the string representation of this object. * * @return the string representation of object */ public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("Label: "); buffer.append(label_); buffer.append(Constants.NEWLINE); buffer.append("Manufacturer ID: "); buffer.append(manufacturerID_); buffer.append(Constants.NEWLINE); buffer.append("Model: "); buffer.append(model_); buffer.append(Constants.NEWLINE); buffer.append("Serial Number: "); buffer.append(serialNumber_); buffer.append(Constants.NEWLINE); buffer.append("Random Number Generator: "); buffer.append(rng_); buffer.append(Constants.NEWLINE); buffer.append("Write protected: "); buffer.append(writeProtected_); buffer.append(Constants.NEWLINE); buffer.append("Login required: "); buffer.append(loginRequired_); buffer.append(Constants.NEWLINE); buffer.append("User PIN initialized: "); buffer.append(userPinInitialized_); buffer.append(Constants.NEWLINE); buffer.append("Restore Key not needed: "); buffer.append(restoreKeyNotNeeded_); buffer.append(Constants.NEWLINE); buffer.append("Clock on Token: "); buffer.append(clockOnToken_); buffer.append(Constants.NEWLINE); buffer.append("Protected Authentication Path: "); buffer.append(protectedAuthenticationPath_); buffer.append(Constants.NEWLINE); buffer.append("Dual Crypto Operations: "); buffer.append(dualCryptoOperations_); buffer.append(Constants.NEWLINE); buffer.append("Token initialized: "); buffer.append(tokenInitialized_); buffer.append(Constants.NEWLINE); buffer.append("Secondary Authentication: "); buffer.append(secondaryAuthentication_); buffer.append(Constants.NEWLINE); buffer.append("User PIN-Count low: "); buffer.append(userPinCountLow_); buffer.append(Constants.NEWLINE); buffer.append("User PIN final Try: "); buffer.append(userPinFinalTry_); buffer.append(Constants.NEWLINE); buffer.append("User PIN locked: "); buffer.append(userPinLocked_); buffer.append(Constants.NEWLINE); buffer.append("User PIN to be changed: "); buffer.append(userPinToBeChanged_); buffer.append(Constants.NEWLINE); buffer.append("Security Officer PIN-Count low: "); buffer.append(soPinCountLow_); buffer.append(Constants.NEWLINE); buffer.append("Security Officer PIN final Try: "); buffer.append(soPinFinalTry_); buffer.append(Constants.NEWLINE); buffer.append("Security Officer PIN locked: "); buffer.append(soPinLocked_); buffer.append(Constants.NEWLINE); buffer.append("Security Officer PIN to be changed: "); buffer.append(soPinToBeChanged_); buffer.append(Constants.NEWLINE); buffer.append("Maximum Session Count: "); buffer .append((maxSessionCount_ == UNAVAILABLE_INFORMATION) ? "" : (maxSessionCount_ == EFFECTIVELY_INFINITE) ? "" : Long.toString(maxSessionCount_)); buffer.append(Constants.NEWLINE); buffer.append("Session Count: "); buffer .append((sessionCount_ == UNAVAILABLE_INFORMATION) ? "" : Long.toString(sessionCount_)); buffer.append(Constants.NEWLINE); buffer.append("Maximum Read/Write Session Count: "); buffer .append((maxRwSessionCount_ == UNAVAILABLE_INFORMATION) ? "" : (maxRwSessionCount_ == EFFECTIVELY_INFINITE) ? "" : Long.toString(maxRwSessionCount_)); buffer.append(Constants.NEWLINE); buffer.append("Read/Write Session Count: "); buffer .append((rwSessionCount_ == UNAVAILABLE_INFORMATION) ? "" : Long.toString(rwSessionCount_)); buffer.append(Constants.NEWLINE); buffer.append("Maximum PIN Length: "); buffer.append(maxPinLen_); buffer.append(Constants.NEWLINE); buffer.append("Minimum PIN Length: "); buffer.append(minPinLen_); buffer.append(Constants.NEWLINE); buffer.append("Total Public Memory: "); buffer .append((totalPublicMemory_ == UNAVAILABLE_INFORMATION) ? "" : Long.toString(totalPublicMemory_)); buffer.append(Constants.NEWLINE); buffer.append("Free Public Memory: "); buffer .append((freePublicMemory_ == UNAVAILABLE_INFORMATION) ? "" : Long.toString(freePublicMemory_)); buffer.append(Constants.NEWLINE); buffer.append("Total Private Memory: "); buffer .append((totalPrivateMemory_ == UNAVAILABLE_INFORMATION) ? "" : Long.toString(totalPrivateMemory_)); buffer.append(Constants.NEWLINE); buffer.append("Free Private Memory: "); buffer .append((freePrivateMemory_ == UNAVAILABLE_INFORMATION) ? "" : Long.toString(freePrivateMemory_)); buffer.append(Constants.NEWLINE); buffer.append("Hardware Version: "); buffer.append(hardwareVersion_); buffer.append(Constants.NEWLINE); buffer.append("Firmware Version: "); buffer.append(firmwareVersion_); buffer.append(Constants.NEWLINE); buffer.append("Time: "); buffer.append(time_); return buffer.toString(); } /** * Compares all member variables of this object with the other object. * Returns only true, if all are equal in both objects. * * @param otherObject The other TokenInfo object. * @return True, if other is an instance of Info and all member variables of * both objects are equal. False, otherwise. * @preconditions * @postconditions */ public boolean equals(java.lang.Object otherObject) { boolean equal = false; if (otherObject instanceof TokenInfo) { TokenInfo other = (TokenInfo) otherObject; equal = (this == other) || (this.label_.equals(other.label_) && this.manufacturerID_.equals(other.manufacturerID_) && this.model_.equals(other.model_) && this.serialNumber_.equals(other.serialNumber_) && (this.maxSessionCount_ == other.maxSessionCount_) && (this.sessionCount_ == other.sessionCount_) && (this.maxRwSessionCount_ == other.maxRwSessionCount_) && (this.rwSessionCount_ == other.rwSessionCount_) && (this.maxPinLen_ == other.maxPinLen_) && (this.minPinLen_ == other.minPinLen_) && (this.totalPublicMemory_ == other.totalPublicMemory_) && (this.freePublicMemory_ == other.freePublicMemory_) && (this.totalPrivateMemory_ == other.totalPrivateMemory_) && (this.freePrivateMemory_ == other.freePrivateMemory_) && this.hardwareVersion_.equals(other.hardwareVersion_) && this.firmwareVersion_.equals(other.firmwareVersion_) && this.time_.equals(other.time_) && (this.rng_ == other.rng_) && (this.writeProtected_ == other.writeProtected_) && (this.loginRequired_ == other.loginRequired_) && (this.userPinInitialized_ == other.userPinInitialized_) && (this.restoreKeyNotNeeded_ == other.restoreKeyNotNeeded_) && (this.clockOnToken_ == other.clockOnToken_) && (this.protectedAuthenticationPath_ == other.protectedAuthenticationPath_) && (this.dualCryptoOperations_ == other.dualCryptoOperations_) && (this.tokenInitialized_ == other.tokenInitialized_) && (this.secondaryAuthentication_ == other.secondaryAuthentication_) && (this.userPinCountLow_ == other.userPinCountLow_) && (this.userPinFinalTry_ == other.userPinFinalTry_) && (this.userPinLocked_ == other.userPinLocked_) && (this.userPinToBeChanged_ == other.userPinToBeChanged_) && (this.soPinCountLow_ == other.soPinCountLow_) && (this.soPinFinalTry_ == other.soPinFinalTry_) && (this.soPinLocked_ == other.soPinLocked_) && (this.soPinToBeChanged_ == other.soPinToBeChanged_)); } return equal; } /** * The overriding of this method should ensure that the objects of this class * work correctly in a hashtable. * * @return The hash code of this object. Gained from the label_, * manufacturerID_, model_ and serialNumber_. * @preconditions * @postconditions */ public int hashCode() { return label_.hashCode() ^ manufacturerID_.hashCode() ^ model_.hashCode() ^ serialNumber_.hashCode(); } }