github.com/linuxboot/fiano@v1.2.0/pkg/amd/psb/signature.go (about) 1 // Copyright 2023 the LinuxBoot Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package psb 6 7 import ( 8 "crypto" 9 "crypto/rsa" 10 "crypto/sha256" 11 "crypto/sha512" 12 "fmt" 13 "strings" 14 ) 15 16 // SignedBlob represents an object whose signature is guaranteed to be validated 17 type SignedBlob struct { 18 signature *Signature 19 signedData []byte 20 } 21 22 // SignedData returns a buffer of signed data held by the SignedBlob object 23 func (b *SignedBlob) SignedData() []byte { 24 return b.signedData 25 } 26 27 // Signature returns the signature of the blob 28 func (b *SignedBlob) Signature() *Signature { 29 return b.signature 30 } 31 32 // NewSignedBlob creates a new signed blob object and validates its signature 33 func NewSignedBlob(signature []byte, signedData []byte, signingKey *Key) (*SignedBlob, error) { 34 structuredKey, err := signingKey.Get() 35 if err != nil { 36 return nil, &SignatureCheckError{signingKey: signingKey, err: fmt.Errorf("could not get structured key data from key in signature object: %w", err)} 37 } 38 39 switch rsaKey := structuredKey.(type) { 40 case *rsa.PublicKey: 41 var ( 42 hashAlg crypto.Hash 43 digest []byte 44 ) 45 switch size := rsaKey.Size(); size { 46 case sha512.Size * 8: 47 hashAlg = crypto.SHA384 48 hash := sha512.New384() 49 hash.Write(signedData) 50 digest = hash.Sum(nil) 51 case sha256.Size * 8: 52 hashAlg = crypto.SHA256 53 hash := sha256.New() 54 hash.Write(signedData) 55 digest = hash.Sum(nil) 56 default: 57 return nil, fmt.Errorf("signature validation for RSA key with size != 4096/2048 bit (%d) is not supported", size) 58 } 59 60 if err := rsa.VerifyPSS(rsaKey, hashAlg, digest, signature, nil); err != nil { 61 return nil, &SignatureCheckError{signingKey: signingKey, err: err} 62 } 63 signature := NewSignature(signature, signingKey) 64 return &SignedBlob{signedData: signedData, signature: &signature}, nil 65 } 66 return nil, fmt.Errorf("signature validation with key type != RSA is not supported") 67 } 68 69 // NewMultiKeySignedBlob validates the signature of a blob against multiple possible keys stored in a KeySet, 70 // returning the key which validates the signature of the blob 71 func NewMultiKeySignedBlob(signature []byte, signedData []byte, keySet KeySet) (*SignedBlob, *Key, error) { 72 allKeyIDs := keySet.AllKeyIDs() 73 for _, keyID := range allKeyIDs { 74 key := keySet.GetKey(keyID) 75 if key == nil { 76 return nil, nil, fmt.Errorf("KeySet is inconsistent, KeyID %s was returned but corresponding key is not present", keyID.Hex()) 77 } 78 79 blob, err := NewSignedBlob(signature, signedData, key) 80 if err == nil { 81 return blob, key, nil 82 } 83 } 84 85 return nil, nil, fmt.Errorf("cannot validate signed blob with any of the %d keys available (%s)", len(allKeyIDs), allKeyIDs.String()) 86 } 87 88 // Signature represents the raw signature bytes of a blob 89 type Signature struct { 90 signature []byte 91 signingKey *Key 92 } 93 94 // String returns a string representation of the signature 95 func (s *Signature) String() string { 96 keyID := s.signingKey.data.KeyID 97 var str strings.Builder 98 fmt.Fprintf(&str, "KeyID: %s\n", keyID.Hex()) 99 fmt.Fprintf(&str, "Signature: 0x%x\n", s.signature) 100 return str.String() 101 } 102 103 // SigningKey returns the signing key associated to the signature 104 func (s *Signature) SigningKey() *Key { 105 return s.signingKey 106 } 107 108 // NewSignature creates a new signature object 109 func NewSignature(signature []byte, signingKey *Key) Signature { 110 return Signature{signature: signature, signingKey: signingKey} 111 } 112 113 // SignatureValidationResult represents the result of a signature validate 114 type SignatureValidationResult struct { 115 signingKey *Key 116 signedElement string 117 err error 118 } 119 120 // String returns a string representation of the signature validation result 121 func (v *SignatureValidationResult) String() string { 122 123 var str strings.Builder 124 fmt.Fprintf(&str, "Signed element: %s\n", v.signedElement) 125 if v.signingKey != nil { 126 keyID := v.signingKey.data.KeyID 127 fmt.Fprintf(&str, "Signing key ID: 0x%s\n", keyID.Hex()) 128 } else { 129 fmt.Fprintf(&str, "Signing key ID: UNKNOWN\n") 130 } 131 if v.err != nil { 132 fmt.Fprintf(&str, "Signature: FAIL (%s)\n", v.err.Error()) 133 } else { 134 fmt.Fprintf(&str, "Signature: OK\n") 135 } 136 return str.String() 137 } 138 139 // SigningKey returns a key that was used to validate the signature 140 func (v *SignatureValidationResult) SigningKey() *Key { 141 return v.signingKey 142 } 143 144 // Error returns a signature verification error if any 145 func (v *SignatureValidationResult) Error() error { 146 return v.err 147 }