/* * Secure Memory / Keystore Exemplification Module * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved * * This module has been overloaded as an example to show: * - Secure memory subsystem initialization/shutdown * - Allocation/deallocation of "slots" in a secure memory page * - Loading and unloading of key material into slots * - Covering of secure memory objects into "black keys" (ECB only at present) * - Verification of key covering (by differentiation only) * - Exportation of keys into secure memory blobs (with display of result) * - Importation of keys from secure memory blobs (with display of result) * - Verification of re-imported keys where possible. * * The module does not show the use of key objects as working key register * source material at this time. * * This module can use a substantial amount of refactoring, which may occur * after the API gets some mileage. Furthermore, expect this module to * eventually disappear once the API is integrated into "real" software. */ #include "compat.h" #include "regs.h" #include "intern.h" #include "desc.h" #include "error.h" #include "jr.h" #include "sm.h" /* Fixed known pattern for a key modifier */ static u8 skeymod[] = { 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 }; /* Fixed known pattern for a key */ static u8 clrkey[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x0f, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; static void key_display(struct device *dev, u8 *label, u16 size, u8 *key) { unsigned i; dev_info(dev, label); for (i = 0; i < size; i += 8) dev_info(dev, "[%04d] %02x %02x %02x %02x %02x %02x %02x %02x\n", i, key[i], key[i + 1], key[i + 2], key[i + 3], key[i + 4], key[i + 5], key[i + 6], key[i + 7]); } int caam_sm_example_init(struct platform_device *pdev) { struct device *ctrldev, *ksdev; struct caam_drv_private *ctrlpriv; struct caam_drv_private_sm *kspriv; u32 unit, units; int rtnval = 0; u8 clrkey8[8], clrkey16[16], clrkey24[24], clrkey32[32]; u8 blkkey8[AES_BLOCK_PAD(8)], blkkey16[AES_BLOCK_PAD(16)]; u8 blkkey24[AES_BLOCK_PAD(24)], blkkey32[AES_BLOCK_PAD(32)]; u8 rstkey8[AES_BLOCK_PAD(8)], rstkey16[AES_BLOCK_PAD(16)]; u8 rstkey24[AES_BLOCK_PAD(24)], rstkey32[AES_BLOCK_PAD(32)]; u8 __iomem *blob8, *blob16, *blob24, *blob32; u32 keyslot8, keyslot16, keyslot24, keyslot32 = 0; blob8 = blob16 = blob24 = blob32 = NULL; /* * 3.5.x and later revs for MX6 should be able to ditch this * and detect via dts property */ ctrldev = &pdev->dev; ctrlpriv = dev_get_drvdata(ctrldev); /* * If ctrlpriv is NULL, it's probably because the caam driver wasn't * properly initialized (e.g. RNG4 init failed). Thus, bail out here. */ if (!ctrlpriv) return -ENODEV; ksdev = ctrlpriv->smdev; kspriv = dev_get_drvdata(ksdev); if (kspriv == NULL) return -ENODEV; /* What keystores are available ? */ units = sm_detect_keystore_units(ksdev); if (!units) dev_err(ksdev, "blkkey_ex: no keystore units available\n"); /* * MX6 bootloader stores some stuff in unit 0, so let's * use 1 or above */ if (units < 2) { dev_err(ksdev, "blkkey_ex: insufficient keystore units\n"); return -ENODEV; } unit = 1; dev_info(ksdev, "blkkey_ex: %d keystore units available\n", units); /* Initialize/Establish Keystore */ sm_establish_keystore(ksdev, unit); /* Initalize store in #1 */ /* * Now let's set up buffers for blobs in DMA-able memory. All are * larger than need to be so that blob size can be seen. */ blob8 = kzalloc(128, GFP_KERNEL | GFP_DMA); blob16 = kzalloc(128, GFP_KERNEL | GFP_DMA); blob24 = kzalloc(128, GFP_KERNEL | GFP_DMA); blob32 = kzalloc(128, GFP_KERNEL | GFP_DMA); if ((blob8 == NULL) || (blob16 == NULL) || (blob24 == NULL) || (blob32 == NULL)) { rtnval = -ENOMEM; dev_err(ksdev, "blkkey_ex: can't get blob buffers\n"); goto freemem; } /* Initialize clear keys with a known and recognizable pattern */ memcpy(clrkey8, clrkey, 8); memcpy(clrkey16, clrkey, 16); memcpy(clrkey24, clrkey, 24); memcpy(clrkey32, clrkey, 32); memset(blkkey8, 0, AES_BLOCK_PAD(8)); memset(blkkey16, 0, AES_BLOCK_PAD(16)); memset(blkkey24, 0, AES_BLOCK_PAD(24)); memset(blkkey32, 0, AES_BLOCK_PAD(32)); memset(rstkey8, 0, AES_BLOCK_PAD(8)); memset(rstkey16, 0, AES_BLOCK_PAD(16)); memset(rstkey24, 0, AES_BLOCK_PAD(24)); memset(rstkey32, 0, AES_BLOCK_PAD(32)); /* * Allocate keyslots. Since we're going to blacken keys in-place, * we want slots big enough to pad out to the next larger AES blocksize * so pad them out. */ if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(8), &keyslot8)) goto freemem; if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(16), &keyslot16)) goto dealloc_slot8; if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(24), &keyslot24)) goto dealloc_slot16; if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(32), &keyslot32)) goto dealloc_slot24; /* Now load clear key data into the newly allocated slots */ if (sm_keystore_slot_load(ksdev, unit, keyslot8, clrkey8, 8)) goto dealloc; if (sm_keystore_slot_load(ksdev, unit, keyslot16, clrkey16, 16)) goto dealloc; if (sm_keystore_slot_load(ksdev, unit, keyslot24, clrkey24, 24)) goto dealloc; if (sm_keystore_slot_load(ksdev, unit, keyslot32, clrkey32, 32)) goto dealloc; /* * All cleartext keys are loaded into slots (in an unprotected * partition at this time) * * Cover keys in-place */ if (sm_keystore_cover_key(ksdev, unit, keyslot8, 8, KEY_COVER_ECB)) { dev_info(ksdev, "blkkey_ex: can't cover 64-bit key\n"); goto dealloc; } if (sm_keystore_cover_key(ksdev, unit, keyslot16, 16, KEY_COVER_ECB)) { dev_info(ksdev, "blkkey_ex: can't cover 128-bit key\n"); goto dealloc; } if (sm_keystore_cover_key(ksdev, unit, keyslot24, 24, KEY_COVER_ECB)) { dev_info(ksdev, "blkkey_ex: can't cover 192-bit key\n"); goto dealloc; } if (sm_keystore_cover_key(ksdev, unit, keyslot32, 32, KEY_COVER_ECB)) { dev_info(ksdev, "blkkey_ex: can't cover 256-bit key\n"); goto dealloc; } /* * Keys should be covered and appear sufficiently "random" * as a result of the covering (blackening) process. Assuming * non-secure mode, read them back out for examination; they should * appear as random data, completely differing from the clear * inputs. So, this will read them back from secure memory and * compare them. If they match the clear key, then the covering * operation didn't occur. */ if (sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8), blkkey8)) { dev_info(ksdev, "blkkey_ex: can't read 64-bit black key\n"); goto dealloc; } if (sm_keystore_slot_read(ksdev, unit, keyslot16, AES_BLOCK_PAD(16), blkkey16)) { dev_info(ksdev, "blkkey_ex: can't read 128-bit black key\n"); goto dealloc; } if (sm_keystore_slot_read(ksdev, unit, keyslot24, AES_BLOCK_PAD(24), blkkey24)) { dev_info(ksdev, "blkkey_ex: can't read 192-bit black key\n"); goto dealloc; } if (sm_keystore_slot_read(ksdev, unit, keyslot32, AES_BLOCK_PAD(32), blkkey32)) { dev_info(ksdev, "blkkey_ex: can't read 256-bit black key\n"); goto dealloc; } if (!memcmp(blkkey8, clrkey8, 8)) { dev_info(ksdev, "blkkey_ex: 64-bit key cover failed\n"); goto dealloc; } if (!memcmp(blkkey16, clrkey16, 16)) { dev_info(ksdev, "blkkey_ex: 128-bit key cover failed\n"); goto dealloc; } if (!memcmp(blkkey24, clrkey24, 24)) { dev_info(ksdev, "blkkey_ex: 192-bit key cover failed\n"); goto dealloc; } if (!memcmp(blkkey32, clrkey32, 32)) { dev_info(ksdev, "blkkey_ex: 256-bit key cover failed\n"); goto dealloc; } key_display(ksdev, "64-bit clear key:", 8, clrkey8); key_display(ksdev, "64-bit black key:", AES_BLOCK_PAD(8), blkkey8); key_display(ksdev, "128-bit clear key:", 16, clrkey16); key_display(ksdev, "128-bit black key:", AES_BLOCK_PAD(16), blkkey16); key_display(ksdev, "192-bit clear key:", 24, clrkey24); key_display(ksdev, "192-bit black key:", AES_BLOCK_PAD(24), blkkey24); key_display(ksdev, "256-bit clear key:", 32, clrkey32); key_display(ksdev, "256-bit black key:", AES_BLOCK_PAD(32), blkkey32); /* * Now encapsulate all keys as SM blobs out to external memory * Blobs will appear as random-looking blocks of data different * from the original source key, and 48 bytes longer than the * original key, to account for the extra data encapsulated within. */ key_display(ksdev, "64-bit unwritten blob:", 96, blob8); key_display(ksdev, "128-bit unwritten blob:", 96, blob16); key_display(ksdev, "196-bit unwritten blob:", 96, blob24); key_display(ksdev, "256-bit unwritten blob:", 96, blob32); if (sm_keystore_slot_export(ksdev, unit, keyslot8, BLACK_KEY, KEY_COVER_ECB, blob8, 8, skeymod)) { dev_info(ksdev, "blkkey_ex: can't encapsulate 64-bit key\n"); goto dealloc; } if (sm_keystore_slot_export(ksdev, unit, keyslot16, BLACK_KEY, KEY_COVER_ECB, blob16, 16, skeymod)) { dev_info(ksdev, "blkkey_ex: can't encapsulate 128-bit key\n"); goto dealloc; } if (sm_keystore_slot_export(ksdev, unit, keyslot24, BLACK_KEY, KEY_COVER_ECB, blob24, 24, skeymod)) { dev_info(ksdev, "blkkey_ex: can't encapsulate 192-bit key\n"); goto dealloc; } if (sm_keystore_slot_export(ksdev, unit, keyslot32, BLACK_KEY, KEY_COVER_ECB, blob32, 32, skeymod)) { dev_info(ksdev, "blkkey_ex: can't encapsulate 256-bit key\n"); goto dealloc; } key_display(ksdev, "64-bit black key in blob:", 96, blob8); key_display(ksdev, "128-bit black key in blob:", 96, blob16); key_display(ksdev, "192-bit black key in blob:", 96, blob24); key_display(ksdev, "256-bit black key in blob:", 96, blob32); /* * Now re-import black keys from secure-memory blobs stored * in general memory from the previous operation. Since we are * working with black keys, and since power has not cycled, the * restored black keys should match the original blackened keys * (this would not be true if the blobs were save in some non-volatile * store, and power was cycled between the save and restore) */ if (sm_keystore_slot_import(ksdev, unit, keyslot8, BLACK_KEY, KEY_COVER_ECB, blob8, 8, skeymod)) { dev_info(ksdev, "blkkey_ex: can't decapsulate 64-bit blob\n"); goto dealloc; } if (sm_keystore_slot_import(ksdev, unit, keyslot16, BLACK_KEY, KEY_COVER_ECB, blob16, 16, skeymod)) { dev_info(ksdev, "blkkey_ex: can't decapsulate 128-bit blob\n"); goto dealloc; } if (sm_keystore_slot_import(ksdev, unit, keyslot24, BLACK_KEY, KEY_COVER_ECB, blob24, 24, skeymod)) { dev_info(ksdev, "blkkey_ex: can't decapsulate 196-bit blob\n"); goto dealloc; } if (sm_keystore_slot_import(ksdev, unit, keyslot32, BLACK_KEY, KEY_COVER_ECB, blob32, 32, skeymod)) { dev_info(ksdev, "blkkey_ex: can't decapsulate 256-bit blob\n"); goto dealloc; } /* * Blobs are now restored as black keys. Read those black keys back * for a comparison with the original black key, they should match */ if (sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8), rstkey8)) { dev_info(ksdev, "blkkey_ex: can't read restored 64-bit black key\n"); goto dealloc; } if (sm_keystore_slot_read(ksdev, unit, keyslot16, AES_BLOCK_PAD(16), rstkey16)) { dev_info(ksdev, "blkkey_ex: can't read restored 128-bit black key\n"); goto dealloc; } if (sm_keystore_slot_read(ksdev, unit, keyslot24, AES_BLOCK_PAD(24), rstkey24)) { dev_info(ksdev, "blkkey_ex: can't read restored 196-bit black key\n"); goto dealloc; } if (sm_keystore_slot_read(ksdev, unit, keyslot32, AES_BLOCK_PAD(32), rstkey32)) { dev_info(ksdev, "blkkey_ex: can't read restored 256-bit black key\n"); goto dealloc; } key_display(ksdev, "restored 64-bit black key:", AES_BLOCK_PAD(8), rstkey8); key_display(ksdev, "restored 128-bit black key:", AES_BLOCK_PAD(16), rstkey16); key_display(ksdev, "restored 192-bit black key:", AES_BLOCK_PAD(24), rstkey24); key_display(ksdev, "restored 256-bit black key:", AES_BLOCK_PAD(32), rstkey32); /* * Compare the restored black keys with the original blackened keys * As long as we're operating within the same power cycle, a black key * restored from a blob should match the original black key IF the * key happens to be of a size that matches a multiple of the AES * blocksize. Any key that is padded to fill the block size will not * match, excepting a key that exceeds a block; only the first full * blocks will match (assuming ECB). * * Therefore, compare the 16 and 32 bit keys, they should match. * The 24 bit key can only match within the first 16 byte block. */ if (memcmp(rstkey16, blkkey16, AES_BLOCK_PAD(16))) { dev_info(ksdev, "blkkey_ex: 128-bit restored key mismatch\n"); rtnval--; } /* Only first AES block will match, remainder subject to padding */ if (memcmp(rstkey24, blkkey24, 16)) { dev_info(ksdev, "blkkey_ex: 192-bit restored key mismatch\n"); rtnval--; } if (memcmp(rstkey32, blkkey32, AES_BLOCK_PAD(32))) { dev_info(ksdev, "blkkey_ex: 256-bit restored key mismatch\n"); rtnval--; } /* Remove keys from keystore */ dealloc: sm_keystore_slot_dealloc(ksdev, unit, keyslot32); dealloc_slot24: sm_keystore_slot_dealloc(ksdev, unit, keyslot24); dealloc_slot16: sm_keystore_slot_dealloc(ksdev, unit, keyslot16); dealloc_slot8: sm_keystore_slot_dealloc(ksdev, unit, keyslot8); /* Free resources */ freemem: kfree(blob8); kfree(blob16); kfree(blob24); kfree(blob32); /* Disconnect from keystore and leave */ sm_release_keystore(ksdev, unit); return rtnval; } EXPORT_SYMBOL(caam_sm_example_init); void caam_sm_example_shutdown(void) { /* unused in present version */ struct device_node *dev_node; struct platform_device *pdev; /* * Do of_find_compatible_node() then of_find_device_by_node() * once a functional device tree is available */ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); if (!dev_node) { dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); if (!dev_node) return; } pdev = of_find_device_by_node(dev_node); if (!pdev) return; of_node_get(dev_node); } static int __init caam_sm_test_init(void) { struct device_node *dev_node; struct platform_device *pdev; /* * Do of_find_compatible_node() then of_find_device_by_node() * once a functional device tree is available */ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); if (!dev_node) { dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); if (!dev_node) return -ENODEV; } pdev = of_find_device_by_node(dev_node); if (!pdev) return -ENODEV; of_node_put(dev_node); caam_sm_example_init(pdev); return 0; } /* Module-based initialization needs to wait for dev tree */ #ifdef CONFIG_OF module_init(caam_sm_test_init); module_exit(caam_sm_example_shutdown); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("FSL CAAM Black Key Usage Example"); MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD"); #endif