diff options
author | subrahmanyaman <subrahmanyaman@google.com> | 2022-12-30 06:23:36 +0000 |
---|---|---|
committer | Subrahmanyaman <subrahmanyaman@google.com> | 2023-03-02 21:32:43 +0000 |
commit | 9ea276d7ad432d10d1dcf4eea898b70642e6b08c (patch) | |
tree | cbde3678641a13c06dc434b50f5db259bd96cfc9 | |
parent | 0ce113724cf47ff0ecde308bd4af9294106f7167 (diff) | |
download | libese-9ea276d7ad432d10d1dcf4eea898b70642e6b08c.tar.gz |
km200: Added documentation as per the review comments on aosp/2082578
Added documentation, specifying the purpose and meaning of each group of constants.
Bug: b/242702664
Test: run vts -m VtsAidlKeyMintTarget
Change-Id: I94e4af0302c9e46e08e6c61baaae12d4080fdbdb
8 files changed, 304 insertions, 66 deletions
diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 146b634..b356643 100644 --- a/ready_se/google/keymint/KM200/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -33,13 +33,12 @@ import org.globalplatform.upgrade.UpgradeManager; * class which stores the data in the flash memory. */ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeListener { - // Magic number version + // Magic number version stored along with provisioned data. This is used to differentiate + // between data before and after the magic number is used. private static final byte KM_MAGIC_NUMBER = (byte) 0x82; // MSB byte is for Major version and LSB byte is for Minor version. public static final short KM_APPLET_PACKAGE_VERSION = 0x0301; - - private static final byte KM_BEGIN_STATE = 0x00; - private static final byte ILLEGAL_STATE = KM_BEGIN_STATE + 1; + // This flag is used to know if card reset happened. private static final short POWER_RESET_MASK_FLAG = (short) 0x4000; // Provider specific Commands @@ -67,11 +66,11 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis INS_KEYMINT_PROVIDER_APDU_START + 18; private static final byte INS_KEYMINT_PROVIDER_APDU_END = 0x1F; - public static final byte BOOT_KEY_MAX_SIZE = 32; - public static final byte BOOT_HASH_MAX_SIZE = 32; + // The length of the provisioned pre shared key. public static final byte SHARED_SECRET_KEY_SIZE = 32; - // Package version. + // Version of the database which is used to differentiate between different version of the + // database. protected short packageVersion; KMAndroidSEApplet() { diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 7245793..e7d8252 100644 --- a/ready_se/google/keymint/KM200/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -31,6 +31,7 @@ import javacard.framework.Util; */ public class KMAttestationCertImpl implements KMAttestationCert { + // The maximum size of the either software or hardware parameters. private static final byte MAX_PARAMS = 30; // DER encoded object identifiers required by the cert. // rsaEncryption - 1.2.840.113549.1.1.1 @@ -51,7 +52,9 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static final byte[] androidExtn = { 0x06, 0x0A, 0X2B, 0X06, 0X01, 0X04, 0X01, (byte) 0XD6, 0X79, 0X02, 0X01, 0X11 }; + // The length of the RSA signature. private static final short RSA_SIG_LEN = 256; + // The maximum length of the ECDSA signature. private static final byte ECDSA_MAX_SIG_LEN = 72; // Signature algorithm identifier - ecdsaWithSha256 - 1.2.840.10045.4.3.2 // SEQUENCE of alg OBJ ID and parameters = NULL. @@ -123,16 +126,17 @@ public class KMAttestationCertImpl implements KMAttestationCert { KMType.ALGORITHM, KMType.PURPOSE }; - + // Below are the constants for the key usage extension. private static final byte keyUsageSign = (byte) 0x80; // 0 bit private static final byte keyUsageKeyEncipher = (byte) 0x20; // 2nd- bit private static final byte keyUsageDataEncipher = (byte) 0x10; // 3rd- bit private static final byte keyUsageKeyAgreement = (byte) 0x08; // 4th- bit private static final byte keyUsageCertSign = (byte) 0x04; // 5th- bit - + // KeyMint HAL Version constant. private static final short KEYMINT_VERSION = 200; + // Attestation version constant. private static final short ATTESTATION_VERSION = 200; - private static final byte[] pubExponent = {0x01, 0x00, 0x01}; + // The X.509 version as per rfc5280#section-4.1.2.1 private static final byte X509_VERSION = (byte) 0x02; // Buffer indexes in transient array @@ -178,7 +182,7 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static byte[] stack; private static short[] swParams; private static short[] hwParams; - + // The maximum size of the serial number. private static final byte SERIAL_NUM_MAX_LEN = 20; private KMAttestationCertImpl() {} @@ -436,8 +440,8 @@ public class KMAttestationCertImpl implements KMAttestationCert { // as positive integer} private static void pushRsaSubjectKeyInfo() { short last = indexes[STACK_PTR]; - pushBytes(pubExponent, (short) 0, (short) pubExponent.length); - pushIntegerHeader((short) pubExponent.length); + pushBytes(KMKeymasterApplet.F4, (short) 0, (short) KMKeymasterApplet.F4.length); + pushIntegerHeader((short) KMKeymasterApplet.F4.length); pushBytes( KMByteBlob.cast(indexes[PUB_KEY]).getBuffer(), KMByteBlob.cast(indexes[PUB_KEY]).getStartOff(), diff --git a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index 6bfc8c3..cb33272 100644 --- a/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/ready_se/google/keymint/KM200/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -47,20 +47,28 @@ import org.globalplatform.upgrade.UpgradeManager; */ public class KMAndroidSEProvider implements KMSEProvider { + // The tag length for AES GCM algorithm. public static final byte AES_GCM_TAG_LENGTH = 16; + // The nonce length for AES GCM algorithm. public static final byte AES_GCM_NONCE_LENGTH = 12; + // AES keysize offsets in aesKeys[] for 128 and 256 sizes respectively. public static final byte KEYSIZE_128_OFFSET = 0x00; public static final byte KEYSIZE_256_OFFSET = 0x01; + // The size of the temporary buffer. public static final short TMP_ARRAY_SIZE = 300; + // The length of the rsa key in bytes. private static final short RSA_KEY_SIZE = 256; - public static final short CERT_CHAIN_MAX_SIZE = 2500; // First 2 bytes for length. - public static final byte SHARED_SECRET_KEY_SIZE = 32; + // Below are the flag to denote device reset events public static final byte POWER_RESET_FALSE = (byte) 0xAA; public static final byte POWER_RESET_TRUE = (byte) 0x00; + // The computed HMAC key size. private static final byte COMPUTED_HMAC_KEY_SIZE = 32; + // The constant 'L' as defiend in + // https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf, page 12. private static byte[] CMAC_KDF_CONSTANT_L; + // Constant to represent 0. private static byte[] CMAC_KDF_CONSTANT_ZERO; - + // KeyAgreement instance. private static KeyAgreement keyAgreement; // AESKey @@ -77,19 +85,21 @@ public class KMAndroidSEProvider implements KMSEProvider { public byte[] tmpArray; // This is used for internal encryption/decryption operations. private static AEADCipher aesGcmCipher; - + // Instance of Signature algorithm used in KDF. private Signature kdf; + // Flag used to denote the power reset event. public static byte[] resetFlag; - + // Instance of HMAC Signature algorithm. private Signature hmacSignature; // For ImportwrappedKey operations. private KMRsaOAEPEncoding rsaOaepDecipher; + // Instance of pool manager. private KMPoolManager poolMgr; - + // Instance of KMOperationImpl used only to encrypt/decrypt the KeyBlobs. private KMOperationImpl globalOperation; // Entropy private RandomData rng; - + // Singleton instance. private static KMAndroidSEProvider androidSEProvider = null; public static KMAndroidSEProvider getInstance() { @@ -491,6 +501,8 @@ public class KMAndroidSEProvider implements KMSEProvider { byte[] context, short contextStart, short contextLength) { + // Note: the variables i and L correspond to i and L in the standard. See page 12 of + // http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf. try { // This is hardcoded to requirement - 32 byte output with two concatenated // 16 bytes K1 and K2. diff --git a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMAsn1Parser.java b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMAsn1Parser.java index b3eacd6..22a16a3 100644 --- a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMAsn1Parser.java +++ b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMAsn1Parser.java @@ -10,6 +10,7 @@ import javacard.framework.Util; */ public class KMAsn1Parser { + // Below are the ASN.1 tag types public static final byte ASN1_OCTET_STRING = 0x04; public static final byte ASN1_SEQUENCE = 0x30; public static final byte ASN1_SET = 0x31; @@ -25,9 +26,11 @@ public class KMAsn1Parser { public static final byte ASN1_UNIVERSAL_STRING = 0x1C; public static final byte ASN1_BMP_STRING = 0x1E; public static final byte IA5_STRING = 0x16; + // OID of the EC P256 curve 1.2.840.10045.3.1.7 public static final byte[] EC_CURVE = { 0x06, 0x08, 0x2a, (byte) 0x86, 0x48, (byte) 0xce, 0x3d, 0x03, 0x01, 0x07 }; + // Constant for rsaEncryption pkcs#1 (1.2.840.113549.1.1.1) and NULL public static final byte[] RSA_ALGORITHM = { 0x06, 0x09, @@ -43,6 +46,7 @@ public class KMAsn1Parser { 0x05, 0x00 }; + // Constant for ecPublicKey (1.2.840.10045.2.1) and prime256v1 (1.2.840.10045.3.1.7) public static final byte[] EC_ALGORITHM = { 0x06, 0x07, @@ -64,7 +68,9 @@ public class KMAsn1Parser { 0x01, 0x07 }; + // The maximum length of email id attribute. public static final short MAX_EMAIL_ADD_LEN = 255; + // Datatable offsets. private static final byte DATA_START_OFFSET = 0; private static final byte DATA_LENGTH_OFFSET = 1; private static final byte DATA_CURSOR_OFFSET = 2; diff --git a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index adc060f..427634c 100644 --- a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -40,42 +40,55 @@ import javacardx.apdu.ExtendedLength; public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLength { // Constants. + // Represents RSA_PUBLIC_EXPONENT value 65537. public static final byte[] F4 = {0x01, 0x00, 0x01}; + // Block size of AES algorithm. public static final byte AES_BLOCK_SIZE = 16; + // Block size of DES algorithm. public static final byte DES_BLOCK_SIZE = 8; + // The Key size in bits for the master key. public static final short MASTER_KEY_SIZE = 128; + // The Key size of the transport key used in importWrappedKey. public static final byte WRAPPING_KEY_SIZE = 32; + // The maximum allowed simultaneous operations. public static final byte MAX_OPERATIONS_COUNT = 4; + // The size of the verified boot key in ROT. public static final byte VERIFIED_BOOT_KEY_SIZE = 32; + // The size of the verified boot hash in ROT. public static final byte VERIFIED_BOOT_HASH_SIZE = 32; - public static final byte BOOT_PATCH_LVL_SIZE = 4; + // The security level of TEE. public static final byte TRUSTED_ENVIRONMENT = 1; // "Keymaster HMAC Verification" - used for HMAC key verification. public static final byte[] sharingCheck = { 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x48, 0x4D, 0x41, 0x43, 0x20, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E }; - // "KeymasterSharedMac" + // The ckdfLabel "KeymasterSharedMac" in hex. public static final byte[] ckdfLabel = { 0x4B, 0x65, 0x79, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4D, 0x61, 0x63 }; - // "Auth Verification" + // The "Auth Verification" string in hex. public static final byte[] authVerification = { 0x41, 0x75, 0x74, 0x68, 0x20, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E }; - // "confirmation token" + // The "confirmation token" string in hex. public static final byte[] confirmationToken = { 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x6B, 0x65, 0x6E }; + // The maximum buffer size for the encoded COSE structures. public static final short MAX_COSE_BUF_SIZE = (short) 1024; // Maximum allowed buffer size for to encode the key parameters - // which is used while creating mac for key paramters. + // which is used while creating mac for key parameters. public static final short MAX_KEY_PARAMS_BUF_SIZE = (short) 3072; // 3K - // Data Dictionary items + // Temporary variables array size to store intermediary results. public static final byte TMP_VARIABLE_ARRAY_SIZE = 5; + // Data Dictionary items + // Maximum Dictionary size. + public static final byte DATA_ARRAY_SIZE = 39; + // Below are the offsets of the data dictionary items. public static final byte KEY_PARAMETERS = 0; public static final byte KEY_CHARACTERISTICS = 1; public static final byte HIDDEN_PARAMETERS = 2; @@ -115,8 +128,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte CONFIRMATION_TOKEN = 36; public static final byte KEY_BLOB_VERSION_DATA_OFFSET = 37; public static final byte CUSTOM_TAGS = 38; - public static final byte DATA_ARRAY_SIZE = 39; - // Keyblob offsets. + // Below are the Keyblob offsets. public static final byte KEY_BLOB_VERSION_OFFSET = 0; public static final byte KEY_BLOB_SECRET = 1; public static final byte KEY_BLOB_NONCE = 2; @@ -124,8 +136,9 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte KEY_BLOB_PARAMS = 4; public static final byte KEY_BLOB_CUSTOM_TAGS = 5; public static final byte KEY_BLOB_PUB_KEY = 6; - // AES GCM constants + // AES GCM Auth tag length to be used while encrypting or decrypting the KeyBlob. public static final byte AES_GCM_AUTH_TAG_LENGTH = 16; + // AES GCM nonce length to be used while encrypting or decrypting the KeyBlob. public static final byte AES_GCM_NONCE_LENGTH = 12; // KEYBLOB_CURRENT_VERSION goes into KeyBlob and will affect all // the KeyBlobs if it is changed. please increment this @@ -134,21 +147,29 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final short KEYBLOB_CURRENT_VERSION = 3; // KeyBlob Verion 1 constant. public static final short KEYBLOB_VERSION_1 = 1; - // KeyBlob array size constants. + // Array sizes of KeyBlob under different versions. + // The array size of a Symmetric key's KeyBlob for Version2 and Version3 public static final byte SYM_KEY_BLOB_SIZE_V2_V3 = 6; + // The array size of a Asymmetric key's KeyBlob for Version2 and Version3 public static final byte ASYM_KEY_BLOB_SIZE_V2_V3 = 7; + // The array size of a Symmetric key's KeyBlob for Version1 public static final byte SYM_KEY_BLOB_SIZE_V1 = 5; + // The array size of a Asymmetric key's KeyBlob for Version1 public static final byte ASYM_KEY_BLOB_SIZE_V1 = 6; + // The array size of a Symmetric key's KeyBlob for Version0 public static final byte SYM_KEY_BLOB_SIZE_V0 = 4; + // The array size of a Asymmetric key's KeyBlob for Version0 public static final byte ASYM_KEY_BLOB_SIZE_V0 = 5; // Key type constants + // Represents the type of the Symmetric key. public static final byte SYM_KEY_TYPE = 0; + // Represents the type of the Asymmetric key. public static final byte ASYM_KEY_TYPE = 1; // SHA-256 Digest length in bits public static final short SHA256_DIGEST_LEN_BITS = 256; // Minimum HMAC length in bits public static final short MIN_HMAC_LENGTH_BITS = 64; - // Provision reporting status + // Below are the constants for provision reporting status public static final short NOT_PROVISIONED = 0x0000; public static final short PROVISION_STATUS_ATTESTATION_KEY = 0x0001; public static final short PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x0002; @@ -161,20 +182,29 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final short PROVISION_STATUS_SE_LOCKED = 0x0100; public static final short PROVISION_STATUS_OEM_PUBLIC_KEY = 0x0200; public static final short PROVISION_STATUS_SECURE_BOOT_MODE = 0x0400; + // This is the P1P2 constant of the APDU command header. protected static final short KM_HAL_VERSION = (short) 0x5000; // OEM lock / unlock verification constants. + // This is the verification label to authenticate the OEM to lock the provisioning for the + // OEM provision commands. protected static final byte[] OEM_LOCK_PROVISION_VERIFICATION_LABEL = { // "OEM Provisioning Lock" 0x4f, 0x45, 0x4d, 0x20, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x6f, 0x63, 0x6b }; + // This is the verification label to authenticate the OEM to unlock the provisioning for the + // OEM provision commands. protected static final byte[] OEM_UNLOCK_PROVISION_VERIFICATION_LABEL = { // "Enable RMA" 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x52, 0x4d, 0x41 }; - // AddRngEntropy + // The maximum size of the seed allowed for the RNG entropy protected static final short MAX_SEED_SIZE = 2048; + // The maximum size of the certificate returned by the generate key command. protected static final short MAX_CERT_SIZE = 3000; + // The maximum size of the encoded key characteristics in CBOR. protected static final short MAX_KEY_CHARS_SIZE = 512; + // The maximum size of the serialized KeyBlob. protected static final short MAX_KEYBLOB_SIZE = 1024; + // The maximum size of the Auth data which is used while encrypting/decrypting the KeyBlob. private static final short MAX_AUTH_DATA_SIZE = (short) 512; // The minimum bits in length for AES-GCM tag. private static final short MIN_GCM_TAG_LENGTH_BITS = (short) 96; @@ -186,20 +216,28 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, 0x65, 0x79 }; + // Constant for Dec 31, 9999 in milliseconds in hex. private static final byte[] dec319999Ms = { (byte) 0, (byte) 0, (byte) 0xE6, (byte) 0x77, (byte) 0xD2, (byte) 0x1F, (byte) 0xD8, (byte) 0x18 }; + // Dec 31, 9999 represented in Generalized time format YYYYMMDDhhmmssZ. + // "99991231235959Z" in hex. Refer RFC 5280 section 4.1.2.5.2 private static final byte[] dec319999 = { 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, }; + // Jan 01, 1970 represented in UTC time format YYMMDDhhmmssZ. + // "700101000000Z" in hex. Refer RFC 5280 section 4.1.2.5.1 private static final byte[] jan01970 = { 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, }; + // The KeyMint name "JavacardKeymintDevice" returned from getHwInfo. private static final byte[] JavacardKeymintDevice = { 0x4a, 0x61, 0x76, 0x61, 0x63, 0x61, 0x72, 0x64, 0x4b, 0x65, 0x79, 0x6d, 0x69, 0x6e, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, }; - private static final byte[] Google = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; + // The KeyMint author name "Google" returned from getHwInfo. + public static final byte[] Google = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; + // Attestation ID tags to be included in attestation record. private static final short[] attTags = { KMType.ATTESTATION_ID_BRAND, KMType.ATTESTATION_ID_DEVICE, @@ -210,8 +248,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe KMType.ATTESTATION_ID_PRODUCT, KMType.ATTESTATION_ID_SERIAL }; - private static final byte OEM_LOCK = 1; - private static final byte OEM_UNLOCK = 0; + // Below are the constants of instructions in APDU command header. // Top 32 commands are reserved for provisioning. private static final byte KEYMINT_CMD_APDU_START = 0x20; // RKP @@ -261,19 +298,32 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // will never be used by the base line code in future. private static final byte INS_KM_VENDOR_START_CMD = (byte) 0xCD; private static final byte INS_KM_VENDOR_END_CMD = (byte) 0xFF; - // ComputeHMAC constants + // The maximum buffer size of combined seed and nonce. private static final byte HMAC_SHARED_PARAM_MAX_SIZE = 64; // Instance of RemotelyProvisionedComponentDevice, used to redirect the rkp commands. protected static KMRemotelyProvisionedComponentDevice rkp; + // Instance of Cbor encoder. protected static KMEncoder encoder; + // Instance of Cbor decoder. protected static KMDecoder decoder; + // Instance of KMRepository class for memory management. protected static KMRepository repository; + // Instance of KMSEProvider for doing crypto operations. protected static KMSEProvider seProvider; + // Holds the instance of KMOperationStates. A maximum of 4 instances of KMOperatioState is + // allowed. protected static KMOperationState[] opTable; + // Instance of KMKeymintDataStore which helps to store and retrieve the data. protected static KMKeymintDataStore kmDataStore; + // Short array used to store the temporary results. protected static short[] tmpVariables; + // Short array used to hold the dictionary items. protected static short[] data; + // Buffer to store the transportKey which is used in the import wrapped key. Import wrapped + // key is divided into two stages 1. BEGIN_IMPORT_WRAPPED_KEY 2. FINISH_IMPORT_WRAPPED_KEY. + // The transportKey is retrieved and stored in this buffer at stage 1) and is later used in + // stage 2). protected static byte[] wrappingKey; /** Registers this applet. */ @@ -4660,7 +4710,6 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // is an error. // 4) If the generated/imported keys are RSA or EC then validity period must be specified. // Device Unique Attestation is not supported. - // Device unique attestation not supported short heapStart = repository.getHeapIndex(); KMTag.assertAbsence( data[KEY_PARAMETERS], @@ -4688,6 +4737,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe cert = makeSelfSignedCert(data[SECRET], data[PUB_KEY], mode, scratchPad); break; case KMType.FAKE_CERT: + // Generate certificate with no signature. cert = makeSelfSignedCert(KMType.INVALID_VALUE, data[PUB_KEY], mode, scratchPad); break; default: @@ -4814,6 +4864,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe } } + // Decode the KeyBlob from CBOR structures to the sub types of KMType. private void decodeKeyBlob(short version, short keyBlob) { // Decode KeyBlob and read the KeyBlob params based on the version. short parsedBlob = @@ -4845,6 +4896,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe readKeyBlobParams(version, parsedBlob); } + // Decrypts the secret key in the KeyBlob. The secret can be a Symmetric or Asymmetric key. private void processDecryptSecret(short version, short appId, short appData, byte[] scratchPad) { data[TEE_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); data[SB_PARAMETERS] = diff --git a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java index 28bb810..56d99a0 100644 --- a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java +++ b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java @@ -68,7 +68,6 @@ public class KMKeymintDataStore implements KMUpgradable { private static final byte DEVICE_STATUS_FLAG_SIZE = 1; private static final short ADDITIONAL_CERT_CHAIN_MAX_SIZE = 2500; // First 2 bytes for length. private static final short BCC_MAX_SIZE = 512; - private static final byte[] zero = {0, 0, 0, 0, 0, 0, 0, 0}; private static KMKeymintDataStore kmDataStore; // Secure Boot Mode public byte secureBootMode; diff --git a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMRemotelyProvisionedComponentDevice.java b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMRemotelyProvisionedComponentDevice.java index b844ce6..ab28cd5 100644 --- a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMRemotelyProvisionedComponentDevice.java +++ b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMRemotelyProvisionedComponentDevice.java @@ -36,84 +36,121 @@ import javacard.framework.Util; */ public class KMRemotelyProvisionedComponentDevice { - // Device Info labels + // Below are the device info labels + // The string "brand" in hex public static final byte[] BRAND = {0x62, 0x72, 0x61, 0x6E, 0x64}; + // The string "manufacturer" in hex public static final byte[] MANUFACTURER = { 0x6D, 0x61, 0x6E, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72 }; + // The string "product" in hex public static final byte[] PRODUCT = {0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74}; + // The string "model" in hex public static final byte[] MODEL = {0x6D, 0x6F, 0x64, 0x65, 0x6C}; + // // The string "device" in hex public static final byte[] DEVICE = {0x64, 0x65, 0x76, 0x69, 0x63, 0x65}; + // The string "vb_state" in hex public static final byte[] VB_STATE = {0x76, 0x62, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65}; + // The string "bootloader_state" in hex. public static final byte[] BOOTLOADER_STATE = { 0x62, 0x6F, 0x6F, 0x74, 0x6C, 0x6F, 0x61, 0x64, 0x65, 0x72, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65 }; + // The string "vb_meta_digest" in hdex. public static final byte[] VB_META_DIGEST = { 0X76, 0X62, 0X6D, 0X65, 0X74, 0X61, 0X5F, 0X64, 0X69, 0X67, 0X65, 0X73, 0X74 }; + // The string "os_version" in hex. public static final byte[] OS_VERSION = { 0x6F, 0x73, 0x5F, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E }; + // The string "system_patch_level" in hex. public static final byte[] SYSTEM_PATCH_LEVEL = { 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x5F, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5F, 0x6C, 0x65, 0x76, 0x65, 0x6C }; + // The string "boot_patch_level" in hex. public static final byte[] BOOT_PATCH_LEVEL = { 0x62, 0x6F, 0x6F, 0x74, 0x5F, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5F, 0x6C, 0x65, 0x76, 0x65, 0x6C }; + // The string "vendor_patch_level" in hex. public static final byte[] VENDOR_PATCH_LEVEL = { 0x76, 0x65, 0x6E, 0x64, 0x6F, 0x72, 0x5F, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5F, 0x6C, 0x65, 0x76, 0x65, 0x6C }; + // The string "version" in hex. public static final byte[] DEVICE_INFO_VERSION = {0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E}; + // The string "security_level" in hex. public static final byte[] SECURITY_LEVEL = { 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5F, 0x6C, 0x65, 0x76, 0x65, 0x6C }; + // The string "fused" in hex. public static final byte[] FUSED = {0x66, 0x75, 0x73, 0x65, 0x64}; - // Verified boot state values + // Below are the Verified boot state values + // The string "green" in hex. public static final byte[] VB_STATE_GREEN = {0x67, 0x72, 0x65, 0x65, 0x6E}; + // The string "yellow" in hex. public static final byte[] VB_STATE_YELLOW = {0x79, 0x65, 0x6C, 0x6C, 0x6F, 0x77}; + // The string "orange" in hex. public static final byte[] VB_STATE_ORANGE = {0x6F, 0x72, 0x61, 0x6E, 0x67, 0x65}; + // The string "red" in hex. public static final byte[] VB_STATE_RED = {0x72, 0x65, 0x64}; - // Boot loader state values + // Below are the boot loader state values + // The string "unlocked" in hex. public static final byte[] UNLOCKED = {0x75, 0x6E, 0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64}; + // The string "locked" in hex. public static final byte[] LOCKED = {0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64}; // Device info CDDL schema version public static final byte DI_SCHEMA_VERSION = 2; + // The string "strongbox" in hex. public static final byte[] DI_SECURITY_LEVEL = { 0x73, 0x74, 0x72, 0x6F, 0x6E, 0x67, 0x62, 0x6F, 0x78 }; + // Represents each element size inside the data buffer. Each element has two entries + // 1) Length of the element and 2) offset of the element in the data buffer. public static final byte DATA_INDEX_ENTRY_SIZE = 4; + // It is the offset, which represents the position where the element is present + // in the data buffer. public static final byte DATA_INDEX_ENTRY_OFFSET = 2; + // Flag to denote TRUE private static final byte TRUE = 0x01; + // Flag to denote FALSE private static final byte FALSE = 0x00; - // RKP Version + // RKP hardware info Version private static final short RKP_VERSION = (short) 0x02; - // Boot params + // Below constants used to denote the type of the boot parameters. Note that these + // constants are only defined to be used internally. private static final byte OS_VERSION_ID = 0x00; private static final byte SYSTEM_PATCH_LEVEL_ID = 0x01; private static final byte BOOT_PATCH_LEVEL_ID = 0x02; private static final byte VENDOR_PATCH_LEVEL_ID = 0x03; + // Configurable flag to denote if Additional certificate chain is supported in the + // RKP server. private static final boolean IS_ACC_SUPPORTED_IN_RKP_SERVER = false; + // The maximum possible output buffer. private static final short MAX_SEND_DATA = 512; - private static final byte[] google = {0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65}; + // The string "Google Strongbox KeyMint 2" in hex. private static final byte[] uniqueId = { - 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x62, 0x6f, 0x78, 0x20, 0x6b, 0x65, 0x79, 0x6d, 0x69, 0x6e, - 0x74 - }; // "strongbox keymint" - // more data or no data - private static final byte MORE_DATA = 0x01; // flag to denote more data to retrieve + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x53, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x62, 0x6f, 0x78, + 0x20, 0x4b, 0x65, 0x79, 0x4d, 0x69, 0x6e, 0x74, 0x20, 0x32 + }; + // Flag to denote more response is available to the clients. + private static final byte MORE_DATA = 0x01; + // Flag to denote no response is available to the clients. private static final byte NO_DATA = 0x00; - // Response processing states + // Below are the response processing states. As the protected data response is huge it is + // sent back incrementally and the clients are responsible to call get response multiple times + // based on MORE_DATA or NO_DATA flags. BCC - Boot Certificate Chain. + // ACC - Additional Certificate Chain. private static final byte START_PROCESSING = 0x00; private static final byte PROCESSING_BCC_IN_PROGRESS = 0x02; private static final byte PROCESSING_BCC_COMPLETE = 0x04; - private static final byte PROCESSING_ACC_IN_PROGRESS = 0x08; // Additional certificate chain. + private static final byte PROCESSING_ACC_IN_PROGRESS = 0x08; private static final byte PROCESSING_ACC_COMPLETE = 0x0A; - // data table + // The data table size. private static final short DATA_SIZE = 512; + // Number of entries in the data table. private static final byte DATA_INDEX_SIZE = 11; - // data offsets + // Below are the data table offsets. private static final byte EPHEMERAL_MAC_KEY = 0; private static final byte TOTAL_KEYS_TO_SIGN = 1; private static final byte KEYS_TO_SIGN_COUNT = 2; @@ -126,12 +163,21 @@ public class KMRemotelyProvisionedComponentDevice { private static final byte RESPONSE_PROCESSING_STATE = 9; private static final byte ACC_PROCESSED_LENGTH = 10; - // data item sizes - private static final byte MAC_KEY_SIZE = 32; + // Below are some of the sizes defined in the data table. + // The size of the Ephemeral Mac key used to sign the rkp public key. + private static final byte EPHEMERAL_MAC_KEY_SIZE = 32; + // The size of short types. private static final byte SHORT_SIZE = 2; + // The size of byte types private static final byte BYTE_SIZE = 1; + // The size of the test mode flag. private static final byte TEST_MODE_SIZE = 1; - // generate csr states + // Below are the different processing stages for generateCSR. + // BEGIN - It is the initial stage where the process is initialized and construction of + // MacedPublickeys are initiated. + // UPDATE - Challenge, EEK and RKP keys are sent to the applet for further process. + // FINISH - MacedPublicKeys are constructed and construction of protected data is initiated. + // GET_RESPONSE - Called multiple times by the client till all the protected data is received. private static final byte BEGIN = 0x01; private static final byte UPDATE = 0x02; private static final byte FINISH = 0x04; @@ -139,16 +185,26 @@ public class KMRemotelyProvisionedComponentDevice { // RKP mac key size private static final byte RKP_MAC_KEY_SIZE = 32; + // This holds the Google ECDSA P256 root key for the Endpoint Encryption Key. public static Object[] authorizedEekRoots; + // Used to hold the temporary results. public short[] rkpTmpVariables; - // variables + // Data table to hold the entries at the initial stages of generateCSR and which are used + // at later stages to construct the response data. private byte[] data; + // Instance of the CBOR encoder. private KMEncoder encoder; + // Instance of the CBOR decoder. private KMDecoder decoder; + // Instance of the KMRepository for memory management. private KMRepository repository; + // Instance of the provider for cyrpto operations. private KMSEProvider seProvider; + // Instance of the KMKeymintDataStore to save or retrieve the data. private KMKeymintDataStore storeDataInst; + // Holds the KMOperation instance. This is used to do multi part update operations. private Object[] operation; + // Holds the current index in the data table. private short[] dataIndex; public KMRemotelyProvisionedComponentDevice( @@ -250,7 +306,10 @@ public class KMRemotelyProvisionedComponentDevice { KMArray resp = KMArray.cast(respPtr); resp.add((short) 0, KMInteger.uint_16(KMError.OK)); resp.add((short) 1, KMInteger.uint_16(RKP_VERSION)); - resp.add((short) 2, KMByteBlob.instance(google, (short) 0, (short) google.length)); + resp.add( + (short) 2, + KMByteBlob.instance( + KMKeymasterApplet.Google, (short) 0, (short) KMKeymasterApplet.Google.length)); resp.add((short) 3, KMInteger.uint_8(KMType.RKP_CURVE_P256)); resp.add((short) 4, KMByteBlob.instance(uniqueId, (short) 0, (short) uniqueId.length)); KMKeymasterApplet.sendOutgoing(apdu, respPtr); @@ -280,6 +339,25 @@ public class KMRemotelyProvisionedComponentDevice { KMKeymasterApplet.sendOutgoing(apdu, arr); } + /** + * This is the first command of the generateCSR. + * Input: + * 1) Number of RKP keys. + * 2) Total length of the encoded CoseKeys (Each RKP key is represented in CoseKey) + * 3) Flag which represents Test mode or Production mode. + * Process: + * 1) Generate Ephemeral mac key and store in the temporary data buffer. This key is + * used to sign Mac_Structure, which contains array of encoded RKP keys, + * 2) Initialize the HMAC operation with the ephemeral mac key and do partial sign of the + * Mac_Structure with the input initial data received. A Multipart update on HMAC is + * called on each updateKey command in the second stage. + * 3) Store the number of RKP keys and the test mode flag in the temporary data buffer. + * 4) Update the phase of the generateCSR function to BEGIN. + * Response: + * Send OK response. + * + * @param apdu Input apdu + */ public void processBeginSendData(APDU apdu) throws Exception { try { initializeDataTable(); @@ -291,8 +369,8 @@ public class KMRemotelyProvisionedComponentDevice { // Re-purpose the apdu buffer as scratch pad. byte[] scratchPad = apdu.getBuffer(); // Generate ephemeral mac key. - short dataEntryIndex = createEntry(EPHEMERAL_MAC_KEY, MAC_KEY_SIZE); - seProvider.newRandomNumber(data, dataEntryIndex, MAC_KEY_SIZE); + short dataEntryIndex = createEntry(EPHEMERAL_MAC_KEY, EPHEMERAL_MAC_KEY_SIZE); + seProvider.newRandomNumber(data, dataEntryIndex, EPHEMERAL_MAC_KEY_SIZE); // Initialize hmac operation. initHmacOperation(); // Partially encode CoseMac structure with partial payload. @@ -322,6 +400,21 @@ public class KMRemotelyProvisionedComponentDevice { } } + /** + * This is the second command of the generateCSR. + * Input: + * CoseMac0 containing the RKP Key + * Process: + * 1) Validate the phase of generateCSR. Prior state should be either BEGIN or UPDATE. + * 2) Validate the number of RKP Keys received against the value received in first command. + * 3) Validate the CoseMac0 structure and extract the RKP Key. + * 4) Do Multipart HMAC update operation with the input as RKP key. + * 5) Update the number of keys received count into the data buffer. + * 6) Update the phase of the generateCSR function to UPDATE. + * Response: + * Send OK response. + * @param apdu Input apdu + */ public void processUpdateKey(APDU apdu) throws Exception { try { // The prior state can be BEGIN or UPDATE @@ -366,6 +459,19 @@ public class KMRemotelyProvisionedComponentDevice { } } + /** + * This is the third command of generateCSR. + * Input: + * EEK chain ordered from Root to Leaf in CoseSign1 format. + * Process: + * 1) Validate the phase of generateCSR. Prior state should be UPDATE. + * 2) Validate the EEK chain and extract the Leaf EEK + * 3) Retrieve the EEK Id and Public key of Leaf EEK and store in the data buffer. + * 4) Update the phase of the generateCSR function to UPDATE. + * Response: + * Send OK response. + * @param apdu Input apdu. + */ public void processUpdateEekChain(APDU apdu) throws Exception { try { // The prior state can be BEGIN or UPDATE @@ -408,6 +514,18 @@ public class KMRemotelyProvisionedComponentDevice { } } + /** + * This is the fourth command of generateCSR. + * Input: + * Challenge + * Process: + * 1) Validate the phase of generateCSR. Prior state should be either UPDATE or BEGIN. + * 2) Store the challenge in the data buffer. + * 3) Update the phase of the generateCSR function to UPDATE. + * Response: + * Send OK response. + * @param apdu Input apdu. + */ public void processUpdateChallenge(APDU apdu) throws Exception { try { // The prior state can be BEGIN or UPDATE @@ -438,8 +556,33 @@ public class KMRemotelyProvisionedComponentDevice { } } - // This function returns pubKeysToSignMac, deviceInfo and partially constructed protected data - // wrapped inside byte blob. The partial protected data contains Headers and encrypted signedMac. + /** + * This is the fifth command of generateCSR. + * Input: + * No input data. + * Process: + * 1) Validate the phase of generateCSR. Prior state should be UPDATE. + * 2) Check if all the RKP keys are received if not throw exception. + * 3) Finalize the HMAC operation and get the signed Mac_Structure which is called as + * pubKeysToSignMac. + * 4) Start constructing the partial protected data. Create a random + * nonce, initialize the AESGCM operation with the session key derived from + * HKDF(ECDH(EPHEMERAL_EC_KEY, EEK_KEY), KdfContext) + * 5) Construct Encrypt_Structure which acts as AAD for AES-GCM operation. + * 6) The payload for the Protected Data is [SignedMac, BCC, ACC]. Construct partial + * SignedMac structure. + * 7) Note that the HAL has to construct the CoseEncrypt structure by collecting all + * the pieces returned from Applet. + * Response: + * OK + * pubKeysToSignMac - Containes the maced RKP public keys. + * deviceInfo - CBOR encoded device info + * protectedHeader - CoseEncrypt protected header + * unProtectedHeader - CoseEncrypt unprotected header. + * ParitalCipherText - partial encrypted payload of CoseEncrypt structure. + * Flag to represent there is more data to retrieve. + * @param apdu Input apdu. + */ public void processFinishSendData(APDU apdu) throws Exception { try { // The prior state should be UPDATE. @@ -492,6 +635,26 @@ public class KMRemotelyProvisionedComponentDevice { } } + /** + * This is the sixth and the last command of generateCSR. This command is called multiple + * times by the HAL until all the cipher data and receipient structure is received. + * Input: + * No input data. + * Process: + * First the BootCertificateChain is processed: Encrypt the boot certificate chain and return + * the BCC. Mark the state as PROCESSING_BCC_COMPLETE. + * Next the AdditionalCertificateChain is processed: Incrementally encrypt ACC and send back + * a chunks of data. Each chunk is 512 bytes. if the processing of ACC is still in progress + * mark the state as PROCESSING_ACC_IN_PROGRESS otherwise mark the state as + * PROCESSING_ACC_COMPLETE. + * Finally construct and return the CoseReceipient structure. + * Response: + * OK + * cipher text: It can be either encrypted bcc or encrypted acc + * Receipient structure: This will be empty will returning the encrypted acc or bcc. + * Flag to represent there is more data to retrieve. + * @param apdu Input apdu. + */ public void processGetResponse(APDU apdu) throws Exception { try { // The prior state should be FINISH. @@ -1572,17 +1735,17 @@ public class KMRemotelyProvisionedComponentDevice { short signatureStart) { short result; if (testMode) { - short macKey = KMByteBlob.instance(MAC_KEY_SIZE); + short macKey = KMByteBlob.instance(EPHEMERAL_MAC_KEY_SIZE); Util.arrayFillNonAtomic( KMByteBlob.cast(macKey).getBuffer(), KMByteBlob.cast(macKey).getStartOff(), - MAC_KEY_SIZE, + EPHEMERAL_MAC_KEY_SIZE, (byte) 0); result = seProvider.hmacSign( KMByteBlob.cast(macKey).getBuffer(), KMByteBlob.cast(macKey).getStartOff(), - MAC_KEY_SIZE, + EPHEMERAL_MAC_KEY_SIZE, data, dataStart, dataLength, diff --git a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMRepository.java b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMRepository.java index dec52eb..9fd2406 100644 --- a/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/ready_se/google/keymint/KM200/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -27,12 +27,15 @@ import javacard.framework.Util; */ public class KMRepository { + // The maximum available heap memory. public static final short HEAP_SIZE = 10000; + // Index pointing from the back of heap. private static short[] reclaimIndex; // Singleton instance private static KMRepository repository; - // Class Attributes + // Heap buffer private byte[] heap; + // Index to the heap buffer. private short[] heapIndex; public KMRepository(boolean isUpgrading) { |