boringssl/crypto/fipsmodule/inject-hash.go

110 lines
3.0 KiB
Go
Raw Normal View History

// Copyright (c) 2017, Google Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
// inject-hash runs a binary compiled against a FIPS module that hasn't had the
// correct hash injected. That binary will fail the power-on integrity check
// and write the calcualted hash value to stderr. This script parses that and
// injects the calcualted value into the given object file.
package main
import (
"bytes"
"encoding/hex"
"errors"
"flag"
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"
)
func do(outPath, arInput, binPath string) error {
cmd := exec.Command(binPath)
out, err := cmd.CombinedOutput()
if err == nil {
return errors.New("binary did not fail self test")
}
lines := strings.Split(string(out), "\n")
if len(lines) < 3 {
return fmt.Errorf("too few lines in output: %q", out)
}
calculatedLine := lines[2]
if !strings.HasPrefix(calculatedLine, "Calculated: ") {
return errors.New("bad prefix of 3rd line: " + calculatedLine)
}
calculatedLine = calculatedLine[12:]
calculated, err := hex.DecodeString(calculatedLine)
if err != nil {
return err
}
if len(calculated) != len(uninitHashValue) {
return fmt.Errorf("unexpected length of calculated hash: got %d, want %d", len(calculated), len(uninitHashValue))
}
arFile, err := os.Open(arInput)
if err != nil {
return err
}
defer arFile.Close()
ar, err := ParseAR(arFile)
if err != nil {
return err
}
if len(ar) != 1 {
return fmt.Errorf("expected one file in archive, but found %d", len(ar))
}
var object []byte
for _, contents := range ar {
object = contents
}
offset := bytes.Index(object, uninitHashValue[:])
if offset < 0 {
return errors.New("did not find uninitialised hash value in object file")
}
if bytes.Index(object[offset+1:], uninitHashValue[:]) >= 0 {
return errors.New("found two occurrences of uninitialised hash value in object file")
}
copy(object[offset:], calculated)
if err := ioutil.WriteFile(outPath, object, 0644); err != nil {
return err
}
return nil
}
func main() {
arInput := flag.String("in", "", "Path to a .a file")
outPath := flag.String("o", "", "Path to output object")
bin := flag.String("bin", "", "Binary compiled with the FIPS module")
flag.Parse()
if err := do(*outPath, *arInput, *bin); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
}