github.com/usbarmory/armory-boot@v0.0.0-20240307133412-208c66a380b9/config/minisign.go (about) 1 // https://github.com/jedisct1/go-minisign 2 // 3 // Copyright (c) 2018-2019 Frank Denis 4 // 5 // This code is a modified version of go-minisign which ignores trusted 6 // comments to support verification of both signify as well as minisign 7 // signatures. 8 // 9 // Use of this source code is governed by the license that can be found at: 10 // https://github.com/jedisct1/go-minisign/blob/master/LICENSE 11 12 package config 13 14 import ( 15 "encoding/base64" 16 "errors" 17 "strings" 18 19 "golang.org/x/crypto/blake2b" 20 "golang.org/x/crypto/ed25519" 21 ) 22 23 type PublicKey struct { 24 SignatureAlgorithm [2]byte 25 KeyId [8]byte 26 PublicKey [32]byte 27 } 28 29 type Signature struct { 30 UntrustedComment string 31 SignatureAlgorithm [2]byte 32 KeyId [8]byte 33 Signature [64]byte 34 TrustedComment string 35 GlobalSignature [64]byte 36 } 37 38 func NewPublicKey(publicKeyStr string) (PublicKey, error) { 39 var publicKey PublicKey 40 41 bin, err := base64.StdEncoding.DecodeString(publicKeyStr) 42 43 if err != nil || len(bin) != 42 { 44 return publicKey, errors.New("Invalid encoded public key") 45 } 46 47 copy(publicKey.SignatureAlgorithm[:], bin[0:2]) 48 copy(publicKey.KeyId[:], bin[2:10]) 49 copy(publicKey.PublicKey[:], bin[10:42]) 50 51 return publicKey, nil 52 } 53 54 func trimCarriageReturn(input string) string { 55 return strings.TrimRight(input, "\r") 56 } 57 58 func DecodeSignature(in string) (Signature, error) { 59 var signature Signature 60 61 lines := strings.SplitN(in, "\n", 4) 62 63 if len(lines) < 2 { 64 return signature, errors.New("Incomplete encoded signature") 65 } 66 67 signature.UntrustedComment = trimCarriageReturn(lines[0]) 68 69 bin1, err := base64.StdEncoding.DecodeString(lines[1]) 70 71 if err != nil || len(bin1) != 74 { 72 return signature, errors.New("Invalid encoded signature") 73 } 74 75 copy(signature.SignatureAlgorithm[:], bin1[0:2]) 76 copy(signature.KeyId[:], bin1[2:10]) 77 copy(signature.Signature[:], bin1[10:74]) 78 79 if len(lines) == 4 { 80 signature.TrustedComment = trimCarriageReturn(lines[2]) 81 82 bin2, err := base64.StdEncoding.DecodeString(lines[3]) 83 84 if err != nil || len(bin2) != 64 { 85 return signature, errors.New("Invalid encoded signature") 86 } 87 88 copy(signature.GlobalSignature[:], bin2) 89 } 90 91 return signature, nil 92 } 93 94 func (publicKey *PublicKey) Verify(bin []byte, signature Signature) (bool, error) { 95 if publicKey.SignatureAlgorithm != [2]byte{'E', 'd'} { 96 return false, errors.New("Incompatible signature algorithm") 97 } 98 99 prehashed := false 100 if signature.SignatureAlgorithm[0] == 0x45 && signature.SignatureAlgorithm[1] == 0x64 { 101 prehashed = false 102 } else if signature.SignatureAlgorithm[0] == 0x45 && signature.SignatureAlgorithm[1] == 0x44 { 103 prehashed = true 104 } else { 105 return false, errors.New("Unsupported signature algorithm") 106 } 107 108 if publicKey.KeyId != signature.KeyId { 109 return false, errors.New("Incompatible key identifiers") 110 } 111 112 if prehashed { 113 h, _ := blake2b.New512(nil) 114 h.Write(bin) 115 bin = h.Sum(nil) 116 } 117 118 if !ed25519.Verify(ed25519.PublicKey(publicKey.PublicKey[:]), bin, signature.Signature[:]) { 119 return false, errors.New("Invalid signature") 120 } 121 122 if len(signature.TrustedComment) != 0 { 123 if !strings.HasPrefix(signature.TrustedComment, "trusted comment: ") { 124 return false, errors.New("Unexpected format for the trusted comment") 125 } 126 127 if !ed25519.Verify(ed25519.PublicKey(publicKey.PublicKey[:]), append(signature.Signature[:], []byte(signature.TrustedComment)[17:]...), signature.GlobalSignature[:]) { 128 return false, errors.New("Invalid global signature") 129 } 130 } 131 132 return true, nil 133 }