github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/boot/stboot/signature.go (about) 1 // Copyright 2018 the u-root 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 stboot 6 7 import ( 8 "crypto" 9 "crypto/rand" 10 "crypto/rsa" 11 "crypto/sha512" 12 "crypto/x509" 13 "encoding/pem" 14 "errors" 15 "fmt" 16 "io/ioutil" 17 ) 18 19 type Signature struct { 20 Bytes []byte 21 Cert *x509.Certificate 22 } 23 24 // Signer is used by BootBall to hash, sign and varify the BootConfigs 25 // with appropriate algorithms 26 type Signer interface { 27 Hash(files ...string) ([]byte, error) 28 Sign(privKey string, data []byte) ([]byte, error) 29 Verify(sig Signature, hash []byte) error 30 } 31 32 // AlwaysValidSigner creates signatures that are always valid. 33 type AlwaysValidSigner struct{} 34 35 // Hash hashes the the provided files. I case of AlwaysValidSigner 36 // just 8 random bytes are returned. 37 func (AlwaysValidSigner) Hash(files ...string) ([]byte, error) { 38 hash := make([]byte, 8) 39 _, err := rand.Read(hash) 40 if err != nil { 41 return nil, err 42 } 43 return hash, nil 44 } 45 46 // Sign signes the provided data with privKey. In case of AlwaysValidSigner 47 // just 8 random bytes are returned 48 func (AlwaysValidSigner) Sign(privKey string, data []byte) ([]byte, error) { 49 sig := make([]byte, 8) 50 _, err := rand.Read(sig) 51 if err != nil { 52 return nil, err 53 } 54 return sig, nil 55 } 56 57 // Verify checks if sig contains a valid signature of hash. In case of 58 // AlwaysValidSigner this is allwazs the case. 59 func (AlwaysValidSigner) Verify(sig Signature, hash []byte) error { 60 return nil 61 } 62 63 // Sha512PssSigner uses SHA512 hashes ans PSS signatures along with 64 // x509 certificates. 65 type Sha512PssSigner struct{} 66 67 // Hash hashes the the provided files. In case of Sha512PssSigner 68 // it is a SHA512 hash. 69 func (Sha512PssSigner) Hash(files ...string) ([]byte, error) { 70 h := sha512.New() 71 for _, file := range files { 72 buf, err := ioutil.ReadFile(file) 73 if err != nil { 74 return nil, err 75 } 76 _, err = h.Write(buf) 77 if err != nil { 78 return nil, err 79 } 80 } 81 return h.Sum(nil), nil 82 } 83 84 // Sign signes the provided data with privKey. In case of Sha512PssSigner 85 // it is a PSS signature. 86 func (Sha512PssSigner) Sign(privKey string, data []byte) ([]byte, error) { 87 buf, err := ioutil.ReadFile(privKey) 88 if err != nil { 89 return nil, err 90 } 91 92 privPem, _ := pem.Decode(buf) 93 key, err := x509.ParsePKCS1PrivateKey(privPem.Bytes) 94 if err != nil { 95 return nil, err 96 } 97 if key == nil { 98 err = fmt.Errorf("key is empty") 99 return nil, err 100 } 101 102 opts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash} 103 104 sig, err := rsa.SignPSS(rand.Reader, key, crypto.SHA512, data, opts) 105 if err != nil { 106 return nil, err 107 } 108 if sig == nil { 109 return nil, fmt.Errorf("signature is nil") 110 } 111 return sig, nil 112 } 113 114 // Verify checks if sig contains a valid signature of hash. 115 func (Sha512PssSigner) Verify(sig Signature, hash []byte) error { 116 opts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash} 117 err := rsa.VerifyPSS(sig.Cert.PublicKey.(*rsa.PublicKey), crypto.SHA512, hash, sig.Bytes, opts) 118 if err != nil { 119 return fmt.Errorf("signature verification failed: %v", err) 120 } 121 return nil 122 } 123 124 // parseCertificate parses certificate from raw certificate. 125 func parseCertificate(raw []byte) (*x509.Certificate, error) { 126 block, _ := pem.Decode(raw) 127 return x509.ParseCertificate(block.Bytes) 128 } 129 130 // certPool returns a x509 certificate pool from raw certificate. 131 func certPool(pem []byte) (*x509.CertPool, error) { 132 certPool := x509.NewCertPool() 133 ok := certPool.AppendCertsFromPEM(pem) 134 if !ok { 135 return nil, errors.New("Failed to parse root certificate") 136 } 137 return certPool, nil 138 } 139 140 // validateCertificate validates cert against certPool. If cert is not signed 141 // by a certificate of certPool an error is returned. 142 func validateCertificate(cert *x509.Certificate, rootCertPEM []byte) error { 143 certPool, err := certPool(rootCertPEM) 144 if err != nil { 145 return err 146 } 147 opts := x509.VerifyOptions{ 148 Roots: certPool, 149 } 150 _, err = cert.Verify(opts) 151 return err 152 }