golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/updater/signify.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package updater
     7  
     8  import (
     9  	"bytes"
    10  	"crypto/ed25519"
    11  	"encoding/base64"
    12  	"encoding/hex"
    13  	"errors"
    14  	"strings"
    15  
    16  	"golang.org/x/crypto/blake2b"
    17  )
    18  
    19  /*
    20   * Generate with:
    21   *   $ b2sum -l 256 *.msi > list
    22   *   $ signify -S -e -s release.sec -m list
    23   *   $ upload ./list.sec
    24   */
    25  
    26  type fileList map[string][blake2b.Size256]byte
    27  
    28  func readFileList(input []byte) (fileList, error) {
    29  	publicKeyBytes, err := base64.StdEncoding.DecodeString(releasePublicKeyBase64)
    30  	if err != nil || len(publicKeyBytes) != ed25519.PublicKeySize+10 || publicKeyBytes[0] != 'E' || publicKeyBytes[1] != 'd' {
    31  		return nil, errors.New("Invalid public key")
    32  	}
    33  	lines := bytes.SplitN(input, []byte{'\n'}, 3)
    34  	if len(lines) != 3 {
    35  		return nil, errors.New("Signature input has too few lines")
    36  	}
    37  	if !bytes.HasPrefix(lines[0], []byte("untrusted comment: ")) {
    38  		return nil, errors.New("Signature input is missing untrusted comment")
    39  	}
    40  	signatureBytes, err := base64.StdEncoding.DecodeString(string(lines[1]))
    41  	if err != nil {
    42  		return nil, errors.New("Signature input is not valid base64")
    43  	}
    44  	if len(signatureBytes) != ed25519.SignatureSize+10 || !bytes.Equal(signatureBytes[:10], publicKeyBytes[:10]) {
    45  		return nil, errors.New("Signature input bytes are incorrect length, type, or keyid")
    46  	}
    47  	if !ed25519.Verify(publicKeyBytes[10:], lines[2], signatureBytes[10:]) {
    48  		return nil, errors.New("Signature is invalid")
    49  	}
    50  	fileLines := strings.Split(string(lines[2]), "\n")
    51  	fileHashes := make(map[string][blake2b.Size256]byte, len(fileLines))
    52  	for index, line := range fileLines {
    53  		if len(line) == 0 && index == len(fileLines)-1 {
    54  			break
    55  		}
    56  		first, second, ok := strings.Cut(line, "  ")
    57  		if !ok {
    58  			return nil, errors.New("File hash line has too few components")
    59  		}
    60  		maybeHash, err := hex.DecodeString(first)
    61  		if err != nil || len(maybeHash) != blake2b.Size256 {
    62  			return nil, errors.New("File hash is invalid base64 or incorrect number of bytes")
    63  		}
    64  		var hash [blake2b.Size256]byte
    65  		copy(hash[:], maybeHash)
    66  		fileHashes[second] = hash
    67  	}
    68  	if len(fileHashes) == 0 {
    69  		return nil, errors.New("No file hashes found in signed input")
    70  	}
    71  	return fileHashes, nil
    72  }