

# 生成固件更新文件和签名
<a name="lorawan-script-fwupdate-sigkey"></a>

本流程的步骤是可选的，取决于您使用的网关。网关制造商会以更新文件或脚本的形式提供自己的固件更新，Basics Station 会在后台运行此脚本。在这种情况下，您很可能会在所使用网关的发布说明中找到固件更新文件。然后，您可以改为使用该更新文件或脚本，然后前进至 [将固件文件上载到 S3 存储桶并添加 IAM 角色](lorawan-upload-firmware-s3bucket.md)。

如果您没有此脚本，下面显示了用于生成固件更新文件的命令。您还可以签署更新，以确保代码未被更改或损坏，并且设备仅运行由受信任的作者发布的代码。

**Topics**
+ [生成固件更新文件](#lorawan-firmware-update-script)
+ [为固件更新生成签名](#lorawan-generate-signature-fwupdate)
+ [查看后续步骤](#lorawan-fwupdate-sigkey-next-steps)

## 生成固件更新文件
<a name="lorawan-firmware-update-script"></a>

在网关上运行的 LoRa Basics Station 软件能够接收 CUPS 响应中的固件更新。如果您没有制造商提供的脚本，请参阅以下固件更新脚本，该脚本是为基于 Raspberry Pi 的 RAKWireless Gateway 编写的。我们有一个基本脚本，而新工作站二进制文件、版本文件和 `station.conf` 将被附加其上。

**注意**  
该脚本特定于 RAKWireless Gateway ，因此您必须根据您使用的网关对其进行调整，以使其适用于您的应用程序。

**基本脚本**  
下面显示了基于 Raspberry Pi 的 RAKWireless Gateway 的基本脚本示例。您可以将以下命令保存在文件 `base.sh` 中，然后在 Raspberry Pi 的 Web 浏览器终端中运行脚本。

```
*#!/bin/bash*
execution_folder=/home/pi/Documents/basicstation/examples/aws_lorawan
station_path="$execution_folder/station"
version_path="$execution_folder/version.txt"
station_conf_path="$execution_folder/station_conf"

# Function to find the Basics Station binary at the end of this script 
# and store it in the station path
function prepare_station()
{
 match=$(grep --text --line-number '^STATION:$' $0 | cut -d ':' -f 1) 
 payload_start=$((match + 1)) 
 match_end=$(grep --text --line-number '^END_STATION:$' $0 | cut -d ':' -f 1) 
 payload_end=$((match_end - 1)) 
 lines=$(($payload_end-$payload_start+1)) 
 head -n $payload_end $0 | tail -n $lines  > $station_path
}

# Function to find the version.txt at the end of this script 
# and store it in the location for version.txt
function prepare_version()
{
  match=$(grep --text --line-number '^VERSION:$' $0 | cut -d ':' -f 1) 
  payload_start=$((match + 1))        
  match_end=$(grep --text --line-number '^END_VERSION:$' $0 | cut -d ':' -f 1) 
  payload_end=$((match_end - 1)) 
  lines=$(($payload_end-$payload_start+1)) 
  head -n $payload_end $0 | tail -n $lines  > $version_path
}

# Function to find the version.txt at the end of this script 
# and store it in the location for version.txt
function prepare_station_conf()
{
 match=$(grep --text --line-number '^CONF:$' $0 | cut -d ':' -f 1) 
 payload_start=$((match + 1)) 
 match_end=$(grep --text --line-number '^END_CONF:$' $0 | cut -d ':' -f 1) 
 payload_end=$((match_end - 1)) 
 lines=$(($payload_end-$payload_start+1)) 
 head -n $payload_end $0 | tail -n $lines  > $station_conf_path
}

# Stop the currently running Basics station so that it can be overwritten
# by the new one
killall station

# Store the different files
prepare_station
prepare_versionp
prepare_station_conf

# Provide execute permission for Basics station binary
chmod +x $station_path

# Remove update.bin so that it is not read again next time Basics station starts
rm -f /tmp/update.bin

# Exit so that rest of this script which has binaries attached does not get executed
exit 0
```

**添加负载脚本**  
在基本脚本中，我们会附加 Basics Station 二进制文件、标识要更新版本的 version.txt 和名为 `addpayload.sh` 脚本中的 `station.conf`。然后，运行此脚本。

```
*#!/bin/bash
*
base.sh > fwstation

# Add station
echo "STATION:" >> fwstation
cat $1 >> fwstation
echo "" >> fwstation
echo "END_STATION:" >> fwstation

# Add version.txt
echo "VERSION:" >> fwstation
cat $2 >> fwstation
echo "" >> fwstation
echo "END_VERSION:" >> fwstation

# Add station.conf
echo "CONF:" >> fwstation
cat $3 >> fwstation
echo "END_CONF:" >> fwstation

# executable
chmod +x fwstation
```

运行这些脚本后，您可以在终端中运行以下命令来生成固件更新文件，`fwstation`。

```
$ ./addpayload.sh station version.txt station.conf
```

## 为固件更新生成签名
<a name="lorawan-generate-signature-fwupdate"></a>

LoRa Basics Station 软件提供带有 ECDSA 签名的已签名固件更新。要支持已签名的更新，您需要：
+ 必须由 ECDSA 私有秘钥生成且少于 128 字节的签名。
+ 用于签名的私有密钥且必须存储在网关中，其文件名格式应为 `sig-%d.key`。建议使用 `sig-0.key` 作为文件名。
+ 私有密钥上的 32 位 CRC。

签名和 CRC 将传递给 适用于 LoRaWAN 的 AWS IoT Core API。要生成以前的文件，可以使用以下脚本，`gen.sh`。该脚本是根据 GitHub 存储库中的 [ basicstaion](https://github.com/lorabasics/basicstation/blob/master/examples/cups/prep.sh) 示例编写的。

```
*#!/bin/bash

*function ecdsaKey() {
    # Key not password protected for simplicity    
    openssl ecparam -name prime256v1 -genkey | openssl ec -out $1
}

# Generate ECDSA key
ecdsaKey sig-0.prime256v1.pem

# Generate public key
openssl ec -in sig-0.prime256v1.pem -pubout -out sig-0.prime256v1.pub

# Generate signature private key
openssl ec -in sig-0.prime256v1.pub -inform PEM -outform DER -pubin | tail -c 64 > sig-0.key

# Generate signature
openssl dgst -sha512 -sign sig-0.prime256v1.pem $1 > sig-0.signature

# Convert signature to base64
openssl enc -base64 -in sig-0.signature -out sig-0.signature.base64

# Print the crc
crc_res=$(crc32 sig-0.key)printf "The crc for the private key=%d\n" $((16#$crc_res))

# Remove the generated files which won't be needed later
rm -rf sig-0.prime256v1.pem sig-0.signature sig-0.prime256v1.pub
```

脚本生成的私有秘钥应保存到网关中。密钥文件采用二进制格式。

```
./gen_sig.sh fwstation 
read EC key
writing EC key
read EC key
writing EC key
read EC key
writing EC key
The crc for the private key=3434210794

$ cat sig-0.signature.base64 
MEQCIDPY/p2ssgXIPNCOgZr+NzeTLpX+WfBo5tYWbh5pQWN3AiBROen+XlIdMScv
AsfVfU/ZScJCalkVNZh4esyS8mNIgA==

$ ls sig-0.key
sig-0.key

$ scp sig-0.key pi@192.168.1.11:/home/pi/Documents/basicstation/examples/iotwireless
```

## 查看后续步骤
<a name="lorawan-fwupdate-sigkey-next-steps"></a>

现在您已经生成了固件和签名，请转到下一个主题，将固件文件 `fwstation` 上载到 Amazon S3 存储桶。存储桶是将固件更新文件作为对象存储的容器。您可以添加 IAM 角色，该角色将授予 CUPS 服务器读取 S3 存储桶中的固件更新文件的权限。