{"id":36796104,"url":"https://github.com/onomondo/nrf-softsim","last_synced_at":"2026-01-12T13:30:06.797Z","repository":{"id":203695780,"uuid":"575880053","full_name":"onomondo/nrf-softsim","owner":"onomondo","description":"Manifest repository of the Onomondo SoftSIM x Nordic nRF91 series integration","archived":false,"fork":false,"pushed_at":"2025-12-10T11:24:36.000Z","size":903,"stargazers_count":43,"open_issues_count":16,"forks_count":13,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-12-10T13:55:56.038Z","etag":null,"topics":["iot","lte-m","nb-iot","nordic-semiconductor","softsim","uicc","zephyr"],"latest_commit_sha":null,"homepage":"https://onomondo.com","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/onomondo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-12-08T14:04:02.000Z","updated_at":"2025-11-26T03:05:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"f49e5b7a-baad-4fb6-81dd-b2e33bba0074","html_url":"https://github.com/onomondo/nrf-softsim","commit_stats":null,"previous_names":["onomondo/nrf-softsim"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/onomondo/nrf-softsim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onomondo%2Fnrf-softsim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onomondo%2Fnrf-softsim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onomondo%2Fnrf-softsim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onomondo%2Fnrf-softsim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/onomondo","download_url":"https://codeload.github.com/onomondo/nrf-softsim/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onomondo%2Fnrf-softsim/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28339120,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["iot","lte-m","nb-iot","nordic-semiconductor","softsim","uicc","zephyr"],"created_at":"2026-01-12T13:30:05.320Z","updated_at":"2026-01-12T13:30:06.721Z","avatar_url":"https://github.com/onomondo.png","language":"C","funding_links":[],"categories":["SIM Cards"],"sub_categories":["eSIM / eUICC"],"readme":"# Onomondo SoftSIM for Nordic nRF91 Series\n\nThe Onomondo SoftSIM is an [Open Source](https://github.com/onomondo/onomondo-uicc) C based UICC implementation, allowing new and innovative cellular device designs to see the light of day in the ever-growing landscape of IoT!\n\nTo integrate this awesome new SoftSIM UICC form factor, we have partnered with Nordic Semiconductor to develop and distribute a new SoftSIM modem interface that supports APDU exchange between the modem and the application processor. For more details and an in-depth explenation, refer to Nordic Semiconductor's [documentation](https://docs.nordicsemi.com/bundle/ncs-latest/page/nrfxlib/nrf_modem/doc/softsim_interface.html).\n\n\n## Quick Setup Guide\n\nThe Onomondo SoftSIM samples for nRF91 Series SiP's can be imported as a Zephyr module within the [nRF Connect SDK](https://www.nordicsemi.com/Products/Development-software/nrf-connect-sdk).\n\nA new SDK can be initiated with the following two commands if you are already a user of west and nrf:\n\n```\nwest init -m https://github.com/onomondo/nrf-softsim.git\nwest update\n```\n\nGetting started with the external profile sample:\n```\ncd modules/lib/onomondo-softsim/samples/softsim_external_profile\nwest build --sysbuild -b nrf9151dk/nrf9151/ns\nwest flash\n```\n\n## Prerequisites\n### Get access to your free Onomondo SoftSIM profile\nSoftSIM profiles are delivered through our API. As this can be a bit cumbersome, we've developed a small tool to make this process easier. The tool is available at [sofsim-cli](https://github.com/onomondo/onomondo-softsim-cli). Additional instructions can be found in the CLI repository.\n\n1. Generate an API key on [app.onomondo.com/api-keys](https://app.onomondo.com/api-keys). Follow the instructions on the app.\n2. Download the `softsim` cli tool for your platform.\n3. Fetch your profile: `./softsim fetch --api-key = \u003cyour_api_key\u003e -n 1`. This will create a `profiles` directory for you with `1` encrypted profile.\n\nEvery time you require a new profile, simply use the `./softsim next --key=\u003cpath to your private key\u003e`. It will look in the `./profiles` folder and decrypt and format a profile. _This command guarantees that a new profile is given each time._\n\n\n## General Setup Guide\n### Table of Contents\n#### Quickstart\n1. [Configure NCS to include SoftSIM libraries in your build system](#setup)\n2. [Set-up your API key to get access to SoftSIM profiles through our API](#get-access-to-your-free-softsim-profiles)\n3. [Configure your project to build with SoftSIM](#configure-and-build)\n4. [Configuring SoftSIM in NCS samples](#general-usage)\n\n#### General\n- [Building and running](#building-flashing-and-running)\n- [SoftSIM and physical SIM selection](#software-sim-selection)\n- [Understanding the SIM - why SoftSIM is possible](#understanding-the-sim---why-softsim-is-possible)\n- [Details on provisioning](#provisioning)\n- [Details on kConfig options](#kconfig-options)\n\n### Getting Started\n\nFor existing toolchains and build systems it is sufficient to update the manifest to point to `west.yml` inside this repository:\n\n```\ncd \u003cncs_base\u003e\ngit clone https://github.com/onomondo/nrf-softsim.git modules/lib/onomondo-softsim\nwest config manifest.path modules/lib/onomondo-softsim/\nwest update\n```\n\nFirst time setting it up? We recommend using the [nRF Connect for Desktop](https://www.nordicsemi.com/Products/Development-tools/nrf-connect-for-desktop) to get the build system correctly set up. Once done, configure the manifest as described above.\n\n\nBonus tip: The Toolchain Manager allows you to easily generate the correct environment variables. Click the small arrow and select `Generate environment script`. The output file contains everything you need to set up the new toolchain.\n\nYour folder structure should look something like:\n```\nncs\n |___ .west\n |___ nrf\n |___ nrfxlib\n |___ modules\n     |___lib\n         |___onomondo-softsim\n         |___ ...\n     |___ ...\n |___ zephyr\n |___ ...\n```\n\n### Configure and Build\n\nThere are currently two samples included in this project to showcase how a SoftSIM profile can be provisioned. It is recommended to start with the *static profile* sample.\n\n#### Static profile sample\n`samples/softsim_static_profile` will provision a profile during the first system initialization. The profile is configured in the `prj.conf`\n\nIn the `prj.conf` you'll find the following options related to the SoftSIM statically provisioned profile. This setup is useful for development, as the profile doesn't have to be re-provisioned every time the device is flashed.\n\n```\nCONFIG_SOFTSIM_STATIC_PROFILE_ENABLE=y\nCONFIG_SOFTSIM_STATIC_PROFILE=\"011208091...\"\n```\n\nRun `./softsim next --key=~/myPrivateKey` (with path to your private key) and grab the output. By default it formats the profile to be accepted by any nRF91 series devices. The profile will look similar to `01120...`. Replace the `CONFIG_SOFTSIM_STATIC_PROFILE` value with your SoftSIM profile.\n\n\nBuild and flash the sample and the device will attach and send data right away.\n\n```\nwest build\nwest flash\n```\n\n#### External profile sample\n`samples/softsim_external_profile` will wait for a profile supplied via UART. After receiving it will be provisioned and the device will reboot to free up the UART port for AT commands.\n\n```\necho \"\u003cmy_profile\u003e\" \u003e /dev/tty.usbmodem\u003cid\u003e\n```\n\nWhich results in:\n```\n*** Booting Zephyr OS build v3.2.99-ncs1 ***\n[00:00:00.610,198] \u003cinf\u003e softsim_sample: SoftSIM sample started.\n[00:00:00.610,656] \u003cinf\u003e softsim_sample: Transfer SoftSIM profile using serial COM port, terminate by newline character (return key)\n*** Booting Zephyr OS build v3.2.99-ncs1 ***\n[00:00:00.555,664] \u003cinf\u003e softsim_sample: SoftSIM sample started.\n[00:00:00.615,875] \u003cinf\u003e softsim_sample: Waiting for LTE connect event.\n[00:00:00.744,140] \u003cinf\u003e softsim_sample: LTE cell changed: Cell ID: -1, Tracking area: -1\n[00:00:01.185,760] \u003cinf\u003e softsim_sample: LTE cell changed: Cell ID: 13358642, Tracking area: 2000\n[00:00:01.308,349] \u003cinf\u003e softsim_sample: RRC mode: Connected```\n+CEREG: 5,\"07D0\",\"00CBD632\",7,,,\"00100011\",\"11100000\"\n[00:00:07.096,221] \u003cinf\u003e softsim_sample: Network registration status: Connected - roaming\n[00:00:07.096,405] \u003cinf\u003e softsim_sample: LTE connected!\n```\n### General usage\n\nFor most samples and applications, it's sufficient to build by executing the following command:\n```_\nwest build -b nrf9151dk/nrf9151/ns -- \"-DOVERLAY_CONFIG=$PATH_TO_ONOMONDO_SOFTSIM/overlay-softsim.conf\"\n```\nWhere `PATH_TO_ONOMONDO_SOFTSIM` is the path of the downloaded Onomondo SoftSIM repository, for example `$HOME/ncs/nrf-softsim-dev`.\n\n#### Note\nSoftSIM is relying on some default data in the storage partition. This section of the flash can be generated and flashed manually (see steps below) or, as we recommend, automatically included by adding `SB_CONFIG_SOFTSIM_BUNDLE_TEMPLATE_HEX=y` to `sysbuild.conf`.\n\nManually generating SoftSIM profile template data:\n1. After building the application, generate the application-specific template profile. `west build -b nrf9151dk/nrf9151/ns -t onomondo_softsim_template`\n2. Flash the application-specific template profile. `west flash --hex-file build/onomondo-softsim/template.hex`\n\nIf the partition table of the application changes, for example due to another partition changing size, the template profile must be rebuilt and flashed again.\nThe partition table can be checked at any time with:\n```\nwest build -t partition_manager_report\n```\n\n#### Note\nSome applications will fail to link with error `zephyr/zephyr_pre0.elf uses VFP register arguments` (for example `modem_shell`). In this case it is required to also enable `CONFIG_FP_SOFTABI=y`. It is suggested to create an additional Kconfig overlay for application specific SoftSIM configurations and add them to `overlay-softsim.conf` inside\nthe application directory.\nThe application can then be built like this:\n```\nwest build -b nrf9151dk/nrf9151/ns -- \"-DOVERLAY_CONFIG=$PATH_TO_ONOMONDO_SOFTSIM/overlay-softsim.conf;overlay-softsim.conf\"\n```\n\n#### Note\nFor very large applications, it is required to disable features in order to reduce the size of the application binary and leave space on Flash for the SIM profile.\nDuring the build step, a Flash overflow error will be reported if this requirement is not satisfied.\nThe same principle applies for RAM requirements.\n\n#### Note\nOnomondo SoftSIM uses the heap memory pool. It is expected that `CONFIG_HEAP_MEM_POOL_SIZE` is at least `30000`, so if the target application also uses the heap, please\nconsider adjusting this Kconfig accordingly.\n\n#### Note\nOnomondo SoftSIM cannot coexist with `CONFIG_SETTINGS` with NVS backend `CONFIG_SETTINGS_NVS`. Please consider switching instead to FCB backend by enabling `CONFIG_SETTINGS_FCB`.\n\n\n### Software SIM selection during runtime\n\nThe Modem is runtime-configurable to use regular SIM and/or SoftSIM (or iSIM if supported). The configuration is done by the AT command `AT%CSUS=2` for Software SIM selection. The configuration can be done only when the Modem is deactivated. When reverting to physical SIM, configure with the AT command `AT%CSUS=0`. SIM selection is committed to NVM after a `AT+CFUN=0`.\n\nWhen enabling SoftSIM, the Software SIM will be selected automatically upon initialization.\n\n\n### About Kconfig options\n\nIsn't completely finalized yet. The following fields should either be `y` selected by SoftSIM or the application developer:\n- Flash access\n- TFM for `psa_crypto`\n- NVS for profile\n\n`CONFIG_SOFTSIM` includes SoftSIM in the build system\n`CONFIG_SOFTSIM_AUTO_INIT` starts the SoftSIM task automatically. This can be omitted and done expicitly in the user application.\n\n\n## Understanding the SIM - why SoftSIM is possible\n\nTo be as brief as possible - a SIM is nothing more than a fancy filesystem with the ability to calculate an authentication response to a given authentication challenge. More about that later.\n\n### Filesystem operations\nFor details - refer to https://www.etsi.org/deliver/etsi_ts/102200_102299/102221/18.00.00_60/ts_102221v180000p.pdf\n\nThe majority of commands that the SIM understands are related to the underlying filesystem. These include, but not limitied to,  `SELECT`, `READ BINARY`, `UPDATE BINARY`, `READ RECORD`, `UPDATE RECORD`, `SEARCH RECORD`. You get the idea. Something about selecting files and either reading them or updating them.\n\nNot all files are free to update. For instance the `IMSI` can only be changed by the operator with the correct PINs - so a SIM also manages access rights. Some rights are unlocked with the PIN - for that `VERIFY PIN` command is issued.\n\n#### The nRF9151 SIM init sequence\nWhat happens when you 'activate' the SIM on your device (`AT+CFUN=41`)? The first many commands follows the same pattern - `00a4....` which is the `SELECT` command followed by `00b0....` which is the `READ BINARY` command.\n\n- `80f20000000168` - `STATUS`\n- `00a408040000022fe20168` - `SELECT` '2fe2' (EF_ICCID)\n- `00b000000a` - `READ BINARY` - Get the actual content of selected fine\n- `00a40804000002` 2f000168 - `SELECT` '2f00' (EF_DIR)\n- `00b2010426` - `READ RECORD`\n- `00a408040000022f050168` - `SELECT` '2f05' (EF_PL) which encodes the Preferred Language\n- `00b000000a` - - `READ BINARY`\n- `00a408040000022f080168` - `SELECT` '2f08' (EF_UMPC) (UICC Maximum Power Consumption)\n\nAnd the list goes on...\n\n\n### The template SIM profile\n\nThe main point here is that EF_DIR, EF_PL, EF_UMPC etc are the same for all SIMs. Only the ICCID and IMSI is different across SIMs when they are fresh out of the factory.\n\nTo accomodate that we've created a bootstrapping filesystem that should be flashed together with the application.\n\n\u003cp align=\"center\"\u003e\n \u003cimg width=\"338\" src=\"https://github.com/onomondo/nrf-softsim/assets/46489969/e77404ed-f8fd-46c8-98d8-054258727b8b\"\u003e\n\u003c/p\u003e\n\n\nThe list of files is fairly involved - but in the end only a subset of files are ever accessed.\n\nInternally this is a NVS partition which is a `key-value` store type. It is pretty compact and generally sufficient. The previous request of reading the `ICCID` internally translates to something similar to:\n\n`00a408040000022fe20168` -\u003e `open('/3f00/2fe2)` -\u003e `nvs_read(id=14)`\n\nWe've made a caching layer as well to avoid i) slow reads and ii) excessive writes to flash. So, the SoftSIM profile data looks something like:\n\n\u003cp align=\"center\"\u003e\n \u003cimg width=\"358\" src=\"https://github.com/onomondo/nrf-softsim/assets/46489969/c03113b3-f41b-41c7-b681-0e2b09f7ee7b\"\u003e\n\u003c/p\u003e\n\n\nThe first entry is used to translate between paths (`'3f00/2fe2`) to an actual `NVS key`. It contains an ordered list of files sorted by frequency of access - i.e. the 'master file, 3f00' is in the top, since it is most frequently accessed.\n\n\nThe list is read and parsed to a linked list - and this makes the base for all cached operations. The order makes the lookup very fast.\n\u003cp align=\"center\"\u003e\n \u003cimg height=\"338\" src=\"https://github.com/onomondo/nrf-softsim/assets/46489969/815529a8-caf4-485f-a752-1a6242bec082\"\u003e\n\u003c/p\u003e\n\n\n### Provisioning\n\nAnd that leads us to provisioning of SIMs.\n\nThe `IMSI/ICCID` should't be a surprise at this point:\n\n```c\n#define IMSI_PATH \"/3f00/7ff0/6f07\"\n#define ICCID_PATH \"/3f00/2fe2\"\n\nint write_profile(...){\n\n  ...\n\n  // find the NVS key based on the cache\n  struct cache_entry *entry = (struct cache_entry * f_cache_find_by_name(IMSI_PATH, \u0026fs_cache);\n\n  // commit directly to NVS\n  nvs_write(\u0026fs, entry-\u003ekey, profile-\u003eIMSI, IMSI_LEN)\n\n  ... // repeat for ICCID and support files\n\n}\n```\n\nAlright, that was the easy part. In reality something else happens _just_ before:\n\n```c\nstruct ss_profile profile = {0};\ndecode_profile(len, profile_r, \u0026profile);\n\n// import to psa_crypto\nss_utils_setup_key(KMU_KEY_SIZE, profile.K, KEY_ID_KI);\nss_utils_setup_key(KMU_KEY_SIZE, profile.KIC, KEY_ID_KIC);\nss_utils_setup_key(KMU_KEY_SIZE, profile.KID, KEY_ID_KID);\n```\n3 keys are written to the KMU. These are related to the authentication and remote SIM OTA commands.\n\nWhen a device finds a network it wants to attach to, something like this happens (simplified version):\n\n\u003cp align=\"center\"\u003e\n\u003cimg height=\"600\" src=\"https://github.com/onomondo/nrf-softsim/assets/46489969/19083bea-2727-48d6-ad50-63f80384e4d8\"\u003e\n\u003c/p\u003e\n\n\nStep 5 is a SIM command as well `AUTHENTICATE EVEN` and it is running the `milenage algorithm` that also creates session keys, checks that the network in fact isn't an imposter, etc.\n\nThe milenage algorithm is `AES` based and we utilize the KMU through the `psa_crypto` API to implement this. This means that the keys are _very_ protected and once written they can't ever be extracted. Instead they are used by reference in the crypto engine.\n\n\n#### Provisioning SoftSIMs\nIs done through a pretty simple interface -\n`nrf_softsim_provision(uint8_t * data, size_t len)` decodes and write the profile to the appropriate places.\nThe profile is fetched from Onomondo's API. The sample uses UART to transfer it.\n\nAt any time the provisioning status can be queried with `nrf_softsim_check_provisioned()`. Handy when boothing up as the device can enter a provision mode based on this.\n\n\n#### Quick recap\n```c\nstruct profile\n{\n  u8[] Ki,\n  u8[] KIC,\n  u8[] KID,\n  u8[] IMSI,\n  u8[] ICCID,\n  u8[] SMSP // SMS related\n}\n```\n\nThe profile encoding is a `TLV` like structure (Tag Length Value) to make it a bit more flexible. Each field in the profile has a tag assigned e.g. `IMSI_TAG=(0x01)`.\n\nThe profile is contructed by encoding `TAG|LEN|DATA[LEN]` for each field and concatinating multple TLV fields:\n\nEncoding the IMSI is done by: `TAG: 1, LEN: 0x12`:\n\nIMSI_TLV: `0112082943051220434955`\n\nWhere the first 4 bytes are recognized as `01(TAG) 12(LEN)` and indeed 18 bytes follow.\n\n\n## Some more details\n\n#### Memory Heaps\n`mem.h`/`ss_heap.c` can now be optionally used to implement custom allocators - i.e. `k_malloc()` to avoid conflict with stdc heap pools. We default to `k_malloc()/k_free()`\n\n#### Non-Volatile Storage (NVS)\nThe main challenge here is that the NVS is a \"key-value\" store i.e. `UINT16 -\u003e void *`. SoftSIM needs a `char * path -\u003e void * data` map.\n\nTo overcome this, the first entry (ID 1) in the NVS will store a mapping from paths to actual ID's.\n\nThe ID is leveraged to encode additional information, i.e. if content is in protected storage instead.\n\n```\nDir entry:\n\n[[ID_1, PATH_LEN, PATH], [ID_n, PATH_LEN, PATH], ...  ]\n\nWhere ID is the actual ID where DATA is stored.\n\nID \u0026 0xFF00 (upper bits) are used for flags, i.e.\n\n#define FS_READ_ONLY         (1UL \u003c\u003c 8)\n#define FS_COMMIT_ON_CLOSE   (1UL \u003c\u003c 7)  // commit changes to NVS on close\n```\nThe inital DIR is designed to prioritize most accessed files as well. Internally, files are cached and in general kept in memory.\n\n`FS_COMMIT_ON_CLOSE` is used for SEQ numbers that should be committed to flash directly to reduce attack vectors.\n\n\n#### SoftSIM integration in application code\nEither call `nrf_softsim_init()` explicitly or let the kernel do it on boot with the config option.\n\nSoftSIM entrypoint starts its own work queue and returns immediately after. The handler installed with `nrf_modem_softsim_req_handler_set()` will enqueue requests, as they come and the work queue will unblock and handle the request. The SoftSIM context will be blocked most of the time. The main interaction happens on boot.\n\n![softsim_nrf_flow](https://github.com/onomondo/nrf-softsim/assets/46489969/7513bb06-99b3-4de4-95bb-34884a9726ed)\n\nPlease note that SoftSIM internally need access to a storage partition. This should be pre-populated with the `template.hex` provided in the samples. The adress in the `template.hex` is hardcoded but can be moved around freely as pleased with an appropriate tool. The location is derived from the devicetree at compile time (` FIXED_PARTITION_DEVICE(NVS_PARTITION)`)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonomondo%2Fnrf-softsim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonomondo%2Fnrf-softsim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonomondo%2Fnrf-softsim/lists"}