SIM7000x and SSL

I designed the Simcom SIM7000x into a product some time ago; although it is a little dated, it still offers an extensive set of features for a remarkably low price. In particular, it combines a (2G, 3G, 4G/LTE) cellular modem with a GPS receiver and supports very low power modes of operation. The problem is the documentation and I’m publishing this post in the hope that it will save others some pain.

First: the grousing:

Like most communication modules, the SIM7000x is controlled via an asynch serial interface using the venerable AT command set dating back to POTS modems. That so many manufacturers still use this 1981 control interface is remarkable (and so awful that I will post about just this issue in the future). There are three particularly bad things about it:

  1. It tries to combine human and M2M communication and, as a result, is terrible at both. For M2M, there is no framing, error checking, data typing, MIB, easy way to separate tokens, or standard error handling.
  2. The data and control streams share the same serial interface so you can’t (easily) interact with the module while it is transferring data (yeah, I know about CMUX).
  3. Because the interface is so old, has been used by many manufacturers, and several standards bodies have attempted to tame it (each differently), there are now gobs of similar commands that leave a confusing and inconsistent interface which is difficult to code to.

Some day, a smart manufacturer is going to fix this. The SIM7000x has a rich set of peripherals, gobs of I/O, memory, and processor power; it could easily deprecate the AT interface and add something sane. A modern interface would support I2C and/or SPI, layered communication protocol, and standard MIB interface. Nevertheless, the SIM7K modules offer a great deal of functionality, are FCC and PTCRB modular certified (so they’re ready to use on carrier networks), and can be purchased for a reasonable price.

My Applications

Nearly all of my design work involves embedded systems (there are often extensive backend server systems too). For the embedded systems, I typically want to establish a connection to a remote server and exchange data; usually using a RESTful or MQTT API in a format like JSON or msgpack. Because the devices are typically remote from the server, I need:

  • secure communication (TLS)
  • server authentication (public key certificates)
  • remote device authentication that can be revoked

The SIM7000x supports all of this, but the specifics are not always obvious or convenient despite the 281 page AT Command Manual and numerous application notes including TCP/IP, SSL, and HTTP(S) Simcom provides. The manuals should probably be much longer and take more time to explain the API architecture and how the commands. I’ll provide an overview below of how to do secure data communications and include discussion of some of the potential areas of misunderstanding. Note: the discussion below assumes you have the latest firmware installed on the module.

LTE Connectivity

In America, GPRS (2G) and EDGE (3G) data networks have been completely discontinued as of the end of 2022. Most low-cost data connectivity now relies on 4G/LTE which the SIM7000x supports. All the major cellular carriers (AT&T, Verizon, T-Mobile, etc.) support LTE and you can buy SIM cards for any carrier to use with the SIM7K modem module. I use the MVNO Velocity/Flolive; which offers multi-carrier SIMs so the device will connect to whatever carrier is available, anywhere in the world it is deployed (i.e. you’re not tied to one carrier’s network).

Let’s look at the AT commands involved in bringing up an LTE data connection:

Initial Startup of the Modem

  • If you are using the DTR wake/sleep functionality, set the DTR pin to wake the modem
  • Send the modem an AT command and wait for OK response to see if it is already awake
  • If the modem does not respond, try a hard reset wait for the RDY prompt
  • If the modem still does not respond, toggle PWRKEY and wait for the RDY prompt
  • Repeat the above a few times until you get a RDY or OK prompt
  • Reset the modem configuration so you’re starting from a known state using the command:
    ATZ (and wait for OK response)
  • Enable sleep mode if you want low power operation (which I usually do) with the command:
    AT+CSCLK=1 (and wait for OK response)
    (note: this is a persistent setting, you only need to do it once – noted as “AUTO_SAVE”)
  • Configure the modem for LTE operation only. There are many 2G, 3G, and 4G bands to be scanned; by limiting the scan to LTE bands, you can dramatically speed up the time it takes to initially find a carrier (the modem will remember after that). Send the command:
    AT+CNMP=38 (and wait for OK response) (AUTO_SAVE)
    (note: this is a persistent setting, you really only need to do it once)
  • Note: if you know which carrier(s) you will be using, you can further speed up the initial carrier discovery by restricting which LTE bands are scanned to only those supported by the carrier.
  • Configure for LTE-M1 only for the same reason (unless you need NBIoT) using the command AT+CMNB=1 (and wait for OK response) (AUTO_SAVE)
  • Disable the Network activity LED if you wish to save power using the command:
    AT+CNETLIGHT=0 (and wait for OK response) (AUTO_SAVE)
  • Gather and cache any data you want about the modem and SIM card using commands like:
    AT+GMM, AT+GMR, AT+GSN, AT+CIMI, AT+CCID

Register with the Carrier Network

  • Check if the modem has already registered on the carrier network using the command AT+COPS? (look for a response like +COPS: 0 which indicates that the modem is searching for a supported carrier or a response like +COPS: 0,0,”AT&T FloLive”,7 which indicates that the modem is connected via LTE.
  • If the modem is not connecting, you can forcibly cycle the modem through de-registering and re-registering with the carrier using the sequence: AT+COPS=2 and wait for OK then AT+COPS=0 and wait for OK.
  • When the modem connects to the carrier, it can send (depending on some other configuration settings) an asynchronous notice like: *PSUTTZ: 24/06/13,22:40:35″,”-16″,1
  • Once AT+COPS? indicates that you’re connected to the carrier, you can check things like the signal strength with the command
    AT+CSQ (and wait for the response like +CSQ:25,99 followed by OK)

Connect to the Packet Data Network

  • Your data provider may be the carrier like AT&T or a third party MVNO like FloLive that uses many carriers. You will need to know the APN for your data provider to get IP connectivity.
  • You can either hardcode an APN (like flolive.net) or, when using LTE, request the APN from the carrier using the command:
    AT+CGNAPN (and wait for a response like +CGNAPN: 1,”flolive.net”).
    Note that not all carriers will provide the (correct) APN so you may be better off hard coding it.
  • Set the APN using the command:
    AT+CSTT=”flolive.net” (and wait for OK) (not persistent)
  • Check to see if the modem has connected to the packet data network using the command: AT+CEREG? (the response that indicates you are connected +CEREG: 0,1 or +CEREG: 0,5 or are not yet connected +CEREG: 0,2 (searching/trying to attach).
  • Handle critical errors such as +CEREG: 0,0 (modem gave up searching for a carrier) or
    +CEREG: 0,3 (registration denied). Generally your options in these cases are limited to periodically de-registering from the carrier network and re-registering
    (as described above with AT+COPS=2 then AT+COPS=0).
  • Once you are connected to the APN, you can connect to the IP network.

Connect to the IP network

  • Check your IP connection status and IP address using the command
    AT+CNACT? (your response will indicate +CNACT: 0,”0.0.0.0″ if not connected or something like +CNACT: 1,”100.64.132.137″ if you are connected)
  • If you don’t have an IP connection yet, use the command:
    AT+CNACT=1 or AT+CNACT=1,”flolive.net” (and wait for the OK response).
    When the connection is made, the modem sends an asynchronous status message:
    +APP PDP: ACTIVE
  • Wait until you are connected and have been assigned an IP address.
  • You can optionally test the connection by pinging your server or a remote host using: AT+SNPING4=”yahoo.com”,5,16,1000 (ping 5 times with a 16-byte packet and 1s timeout). If you’re connected, you’ll see 5 responses like:
    +SNPING4: 1, 74.6.231.20,194 (indicating a 194ms ping time)

SSL/TLS connection

  • The SSL stack supports several (6) different configurations (contexts). Each context is numbered (ctxindex 0..5). Use the following command to set context 0 to use TLS1.2:
    AT+CSSLCFG=”sslversion”,0,3
  • If your application doesn’t set the date/time on the modem, you can tell the modem to ignore date/time when evaluating the validity of security certificates using the command:
    AT+CSSLCFG=”ignorertctime”,0,1
  • If your server serves multiple domains from the same machine (e.g. apache virtual servers), you can indicate the server name to tell the stack which certificate should be used:
    AT+SSLCFG=”sni”,0,”myserver.mydomain.com”

Configure Connection parameters

  • Configure keep-alive messages depending on your server configuration needs to prevent the connection from automatically closing:
    AT+CACFG=”KEEPALIVE”,1,30,30,1

Establish a secure TCP connection to the server

  • You can configure several simultaneous connections; each is identified via connection ID (cid). Note: the connection cid is different from the context (each cid should reference a context).
  • Close any prior connection and clear connection settings
    AT+CACLOSE=0 (and wait for OK or ERROR response)
  • Configure connection 0 to use SSL:
    AT+CASSLCFG=0,”ssl”,1 (and wait for OK response)
  • If you have installed a server or CA certificate in the modem (see details below), you can configure the SSL connection to authenticate the server using that certificate so it will only connect to the real server:
    AT+CASSLCFG=0,”cacert”,”myCA.crt” (and wait for OK response)
  • If your server certificate is self-signed (typically with a very long expiration date), you may need to tell the stack to ignore the certificate expiration:
    AT+CASSLCFG=0,”ignorertctime”,0,1 (and wait for OK response)
  • Configure the connection timeout:
    AT+CASSLCFG=0,”timeout”,30000 (and wait for OK response)
  • For debugging, you can check the configuration:
    AT+CASSLCFG?
  • Open a TCP connection to the server
    AT+CAOPEN=0,”TCP”,”myserver.com”,443 (and wait for response: +CAOPEN: 0,0)
    (<cid>,<result> where rslt 0=success, >0=fail; note: 24..26 indicate certificate mismatch)

Send data to the server

  • Send your request data to the server (note specification of the number of bytes you will send)
    AT+CASEND=0,186 (wait for a ‘>’ prompt indicating the modem is ready to receive the data)
  • Send the data and wait for the asynchronous completion indication: +CADATAIND:0
  • Request response information from the server. E.g. to request 1000 bytes of response data:
    AT+CARECV=0,1000
  • You can check the connection status if desired:
    AT+CASTATE? (returns +CASTATE: 0,0 (disconnected) or +CASTATE: 0,1 (connected)
  • Close the connection
    AT+CACLOSE=0 (and wait for OK response)
  • Note: to connect again you must again send the AT+CASSLCFG configuration commands; you don’t need to re-configure the AT+CSSLCFG commands; and re-connect via AT+CAOPEN.

Installing a server certificate

For security, it’s important that the communications be sent over a secure channel so they can’t be stolen or corrupted in transit. The TLS connection does this for you using public key cryptography and a Diffie-Helman key exchange whereby the server and your modem agree on an encryption key to be used during the session.

However, it’s also critical that you authenticate the server (i.e. confirm that the server you are communicating privately with is the actual server you intend to be communicating with). This is also done using public key cryptography and certificates. To do this, you must store a public key for your server or for a master authority on the modem and tell the modem to use that public key to check that a signed certificate supplied by the server when you connect to it is valid for the public key you’ve stored in the modem. Only a server that holds the matching private key can provide a proper certificate signature.
A cool feature of certificates is that they can be chained: an higher-level authority can sign a certificate for your server and if you trust that authority, you can trust the server certificate. This means that you can store the public key for that higher Certificate Authority (CA) and then trust any server certificate that has been signed by the CA. The CA is often called the “root of trust”.

Websites typically pay a certificate authority like DigiCert or Google Trust Services to sign their server certificates. Web browsers come with the public keys for most popular certificate authorities so when you connect to a website, the site can automatically be authenticated. Unfortunately, those CA certificates usually have a short lifetime to protect against the possibility that they may be compromised. This is not a big deal since browsers are regularly updated and those updates include new certificates. However, it’s a problem for embedded devices that may not receive frequent updates.

For your own servers and devices, it may be preferable to generate your own certificates (aka self-signed certificates). You can even generate a public/private key pair for your own certificate authority which you can then use to sign and update many server certificates. Then if the public key for your own CA is stored on the modem, it can authenticate any servers you issue certificates to. Your CA can also have a very long lifetime (e.g. 50 years) so that the public key stored in your modem will be valid for the life of the product. The easiest way to create CA and server certificates is using openssl (I’ll make another post about that if there’s interest). To install a server or CA certificate in the modem (both are referred to as a “cacert” in the modem), it must be loaded into the modem’s file system and then converted to a format used by the modem:

  • Initialize a file system buffer:
    AT+CFSINIT
  • Prepare to write the file to the “customer” portion of the modem’s file system (3), 0 indicates overwrite if file existed, 765 is the certificate file size in bytes (change this to the size of your certificate), 2000 is the timeout in ms for the entire download.
    AT+CFSWFILE=3,”myCA.crt”,0,765,2000 (wait for DOWNLOAD response)
  • Send the certificate file in PEM format (starts with —–BEGIN CERTIFICATE—–\n and end with —–END CERTIFICATE—–\n). Note that in most cases, you can get the certificate for your server by visiting the server from a web browser like Firefox. Click on the lock icon, then Connection Secure, then More Information, then View Certificate. There will be links to download the server certificate or the chain of certificates (starts with rootCA) in PEM format.
  • Free the file system buffer:
    AT+CFSTERM (and wait for OK response)
  • Convert the CA certificate format:
    AT+CSSLCFG=”convert”,2,”myCA.crt” (and wait for OK response)
  • You can check the file size or read it to confirm it has been successfully received using:
    AT+CFSGFIS=3,”myCA.crt” (returns +CFSGFIS: 765\r\n\r\nOK\r\n\r\n)
    OR
    AT+CFSINIT (wait for OK response)
    AT+CFSRFILE=3,”myCA.crt”,0,765,0
    (returns +CFSRFILE: 765\r\n … file contents … \r\n\r\nOK\r\n\r\n)
    AT+CFSTERM
  • Note that if you are using the HTTP(S) APIs for the modem (not covered in this post), you can configure them persistently to use this certificate using:
    AT+SHSSL=0,”myCA.crt” (and wait for OK response) (AUTO_SAVE)

Network Attached Storage (NAS)

Everyone uses cloud storage these days, but I still find local storage useful, especially for large files like photos, videos, music and such. For local storage, I use network attached storage (NAS): a black box with redundant hard drives that is connected to my network. Anyone on the network can access the storage (assuming they have the appropriate permissions).

The NAS box should have at least 2 drives configured as RAID1 or 3 or more drives configured as RAID5 so that there is redundancy: if a hard drive fails (and it will), the information is mirrored on the other drive(s); this allows you to replace the failed drive with no loss of data. The NAS is always online making it a convenient place to backup the drives of desktops/laptops.

Note: it’s important to use hard drives designed for NAS storage (always on) such as the Western Digital Red NAS series or Seagate Exos series.

Although you can make any Linux computer a NAS, I’ve found dedicated NAS boxes to be very useful; they typically use little power, take little space, are quiet, and are meant to operate continuously for years. I’ve had quite a few NAS boxes made by D-Link starting with their DNS-321 and have now moved to a QNAP NAS.

QNAP TS-464

As of November 2024, I moved to using a QNAP TS-464-8G (see: datasheet). There was nothing wrong with the old DNS-320L which is still an amazing NAS, but I wanted something faster. The TS-464 is 10 years newer and is simply better in every dimension:

  • Celeron N5095 quad-core up to 2.9GHz
  • 8GB DDR4 RAM (expandable to 16-64GB)
  • Dual 2.5GbE Ethernet (can support 10GbE via expansion card)
  • Dual USB 3.2 Gen 2 (10Gbps)
  • 4x HDD bays
  • 2x NVMe slots
  • Advanced software including automatic snapshots
  • NASCompares Reviews: 2022, 2024
  • Should reach 280MB/s+ using a single 2.5GbE port
    (with a 2.5GbE switch)

I’ve outfitted the NAS with:

  • 16GB of DDR4 RAM (it came with 8GB and I added a spare 8GB SO-DIMM)
  • 3x Seagate Exos X16 ST14000NM005G 14TB hard disk drives
    (configured as RAID5 yielding roughly 25TB of net storage)
  • A spare Samsung Evo 970 Plus 1TB NVMe drive

  • Poor support for SFTP. although QNAP runs a custom linux variant, it is somewhat locked down and is missing some surprising things. For example, I use proxmox VMs for most of my server functions (and even some virtual workstations). Proxmox is awesome. Among other things, it makes it easy to make backups of any VM that you can easily restore, even to another machine (backups live in /var/lib/vz/dump). With my old NAS, I would create the VM backup(s) and have the NAS (which is in my secure network) sftp to the proxmox VM (which might be outside my secure network if it runs servers exposed to the internet) and download the backup file(s). Bizarrely, the QNAP NAS doesn’t come with an sftp client; instead they want you to use a package called QuFTP which only supports FTPS (which is less secure than sftp). It supports an sftp daemon (you can sftp into the NAS) – you’ll need to enable ssh access via the GUI and your user account in /etc/ssh/sshd_config (add it to the AllowUsers line). However, I don’t want the insecure machine to have ssh access to the secure machine and the sftp access seems problematic (it often drops the connection mid-transfer).

Drives

For the first time ever, I bought used (factory re-certified Seagate Exos) drives because they were considerably less expensive and RAID5 should provide protection against any one drive failing. They are warrantied for 5 years by the vendor and I plan to rotate them out for use as permanent backup drives before their end of warrany. I bought the drives from goharddrive.com for $130 each (total: $390 including tax, shipping, and 5 year warranty). The drives arrived well packed; I ran the full SMART test (which took 12+ hours) and they checked out OK; their date of manufacture was mid 2021 (about 3 years old). We’ll see.

The NAS (without drives) cost $469+tax from amazon on black Friday. The NVMe drive and extra 8GB were spare hardware I already had. The HDDs cost $390 so, in total, I spent $859 for this 25TB of RAID 5 storage. If the drives hold up well, I’ll order a few more for use as a cold spare and for backups.

DNS-320L
In 2024, I retired my beloved DNS-320L which was released in 2012 but is still perfectly usable (thanks to Alt-F firmware…see below). I’d installed two WD Red 4TB drives and still have loads of storage left over. It’s getting a little long-in-the-tooth, and the performance is a bit lacking (36MB/s read vs. theoretical 100MB/s maximum on GbE) but for most of my purposes it was still fine.

Alt-F Firmware
The DNS-320L is ancient and the software that it comes with is hopelessly out of date for a range of reasons. Fortunately, you can replace the stock firmware with the open-source Linux-based Alt-F firmware. This completely replaces the D-Link firmware and provides the core functionality you need (web interface, modern SAMBA file shares, etc.). The project is available from Sourceforge and offers good performance on a variety of older DLink NAS platforms (see performance comparison)

SFTP throughput
When copying files to the NAS via SFTP from my server nodes, I only get about 8MB/s throughput:

This is odd because when using SMB to transfer files from the NAS, I get a sustained 36-40 MB/s, so it appears to be a problem with the SFTP implementation.

Other NAS Resources

  • https://www.pcmag.com/picks/the-best-nas-network-attached-storage-devices
  • https://nascompares.com/
  • https://www.smallnetbuilder.com/tools/finders/nas/view/