boringssl/crypto/fipsmodule/inject-hash.go
Adam Langley fd49993c3b First part of the FIPS module.
Change-Id: Ic3a91ccd2c8cdc364740f256fdb8a7ff66177947
Reviewed-on: https://boringssl-review.googlesource.com/14506
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
2017-04-07 00:05:34 +00:00

125 lines
3.5 KiB
Go

// 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"
)
// uninitHashValue is the default hash value that we inject into the module.
// This value need only be distinct, i.e. so that we can safely
// search-and-replace it in an object file. This must match the value in bcm.c.
var uninitHashValue = [32]byte{
0x5f, 0x30, 0xd1, 0x80, 0xe7, 0x9e, 0x8f, 0x8f, 0xdf, 0x8b, 0x93, 0xd4, 0x96, 0x36, 0x30, 0xcc, 0x30, 0xea, 0x38, 0x0f, 0x75, 0x56, 0x9a, 0x1b, 0x23, 0x2f, 0x7c, 0x79, 0xff, 0x1b, 0x2b, 0xca,
}
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 := NewAR(arFile)
for {
header, err := ar.Next()
if err != nil {
return errors.New("error reading from archive file: " + err.Error())
}
if len(header.Name) > 0 {
break
}
if _, err := ioutil.ReadAll(ar); err != nil {
return errors.New("error reading from archive file: " + err.Error())
}
}
object, err := ioutil.ReadAll(ar)
if err != nil {
return err
}
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)
}
}