Skip to content

Commit

Permalink
Suppport to verify aboot swi image for secure boot (sonic-net#969)
Browse files Browse the repository at this point in the history
* Suppport to verify aboot swi image for secure boot

* Simplify the code

* Fix not return value bug

* Add m2crypto to setup.py

* Change to only verify the image signed by a correct certificate
  • Loading branch information
xumia authored Jun 30, 2020
1 parent 16a33f2 commit aae89b7
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 2 deletions.
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@
# - tabulate
install_requires=[
'click',
'natsort'
'natsort',
'm2crypto'
],
setup_requires= [
'pytest-runner'
Expand Down
50 changes: 49 additions & 1 deletion sonic_installer/bootloader/aboot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
Bootloader implementation for Aboot used on Arista devices
"""

import base64
import collections
import os
import re
import subprocess
import sys
import zipfile

import click

from M2Crypto import X509

from ..common import (
HOST_PATH,
IMAGE_DIR_PREFIX,
Expand All @@ -18,6 +23,12 @@
from .bootloader import Bootloader

_secureboot = None

# For the signature format, see: https://github.com/aristanetworks/swi-tools/tree/master/switools
SWI_SIG_FILE_NAME = 'swi-signature'
SWIX_SIG_FILE_NAME = 'swix-signature'
ISSUERCERT = 'IssuerCert'

def isSecureboot():
global _secureboot
if _secureboot is None:
Expand Down Expand Up @@ -114,11 +125,48 @@ def get_binary_image_version(self, image_path):
def verify_binary_image(self, image_path):
try:
subprocess.check_call(['/usr/bin/unzip', '-tq', image_path])
# TODO: secureboot check signature
return self._verify_secureboot_image(image_path)
except subprocess.CalledProcessError:
return False

def _verify_secureboot_image(self, image_path):
if isSecureboot():
cert = self.getCert(image_path)
return cert is not None
return True

@classmethod
def getCert(cls, swiFile):
with zipfile.ZipFile(swiFile, 'r') as swi:
try:
sigInfo = swi.getinfo(cls.getSigFileName(swiFile))
except KeyError:
# Occurs if SIG_FILE_NAME is not in the swi (the SWI is not signed properly)
return None
with swi.open(sigInfo, 'r') as sigFile:
for line in sigFile:
data = line.split(':')
if len(data) == 2:
if data[0] == ISSUERCERT:
try:
base64_cert = cls.base64Decode(data[1].strip())
return X509.load_cert_string(base64_cert)
except TypeError:
return None
else:
sys.stderr.write('Unexpected format for line in swi[x]-signature file: %s\n' % line)
return None

@classmethod
def getSigFileName(cls, swiFile):
if swiFile.lower().endswith(".swix"):
return SWIX_SIG_FILE_NAME
return SWI_SIG_FILE_NAME

@classmethod
def base64Decode(cls, text):
return base64.standard_b64decode(text)

@classmethod
def detect(cls):
with open('/proc/cmdline') as f:
Expand Down

0 comments on commit aae89b7

Please sign in to comment.