

# 產生韌體更新檔案和簽章
<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 閘道所撰寫的。我們有一個基礎指令碼，而且新的工作站二進位檔、版本檔案，以及 `station.conf` 會附加至其中。

**注意**  
此指令碼是 RAKWireless 閘道特有的，因此您必須改編它，以適應您的應用程序，這取決於您正在使用的閘道。

**基礎指令碼**  
下列顯示 Raspberry Pi 型 RAKWireless 閘道的範例基礎指令碼。您可以將下列命令儲存在檔案 `base.sh` 中，然後在 Raspberry Pi 網頁瀏覽器的終端機中執行指令碼。

```
*#!/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 將傳遞至 AWS IoT Core for LoRaWAN API。若要產生先前的檔案，您可以使用下列指令碼 `gen.sh`，此指令碼是由 GitHub 儲存庫中的 [basicstation](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 儲存貯體中的韌體更新檔案。