in util/fipstools/acvp/acvptool/acvp.go [532:813]
func main() {
flag.Parse()
var args []string
if *waitForDebugger {
args = append(args, "--wait-for-debugger")
}
middle, err := subprocess.New(*wrapperPath, args...)
if err != nil {
log.Fatalf("failed to initialise middle: %s", err)
}
defer middle.Close()
if *waitForDebugger {
log.Printf("attach to process %d to continue", middle.PID())
}
configBytes, err := middle.Config()
if err != nil {
log.Fatalf("failed to get config from middle: %s", err)
}
var supportedAlgos []map[string]interface{}
if err := json.Unmarshal(configBytes, &supportedAlgos); err != nil {
log.Fatalf("failed to parse configuration from Middle: %s", err)
}
if len(*katFilePath) > 0 {
if err := katemitter.EmitToFile(*katFilePath); err != nil {
log.Fatalf("failed to start kat emitter: %v", err)
}
defer katemitter.Close()
}
if *dumpRegcap {
nonTestAlgos := make([]map[string]interface{}, 0, len(supportedAlgos))
for _, algo := range supportedAlgos {
if value, ok := algo["acvptoolTestOnly"]; ok {
testOnly, ok := value.(bool)
if !ok {
log.Fatalf("modulewrapper config contains acvptoolTestOnly field with non-boolean value %#v", value)
}
if testOnly {
continue
}
}
nonTestAlgos = append(nonTestAlgos, algo)
}
regcap := []map[string]interface{}{
map[string]interface{}{"acvVersion": "1.0"},
map[string]interface{}{"algorithms": nonTestAlgos},
}
regcapBytes, err := json.MarshalIndent(regcap, "", " ")
if err != nil {
log.Fatalf("failed to marshal regcap: %s", err)
}
os.Stdout.Write(regcapBytes)
os.Stdout.WriteString("\n")
return
}
if len(*jsonInputFile) > 0 {
if err := processFile(*jsonInputFile, supportedAlgos, middle); err != nil {
log.Fatalf("failed to process input file: %s", err)
}
return
}
var requestedAlgosFlag string
// The output file to which expected results are written, if requested.
var expectedOut *os.File
// A tee that outputs to both stdout (for vectors) and the file for
// expected results, if any.
var fetchOutputTee io.Writer
if len(*runFlag) > 0 && len(*fetchFlag) > 0 {
log.Fatalf("cannot specify both -run and -fetch")
}
if len(*expectedOutFlag) > 0 && len(*fetchFlag) == 0 {
log.Fatalf("-expected-out can only be used with -fetch")
}
if len(*runFlag) > 0 {
requestedAlgosFlag = *runFlag
} else {
requestedAlgosFlag = *fetchFlag
if len(*expectedOutFlag) > 0 {
if expectedOut, err = os.Create(*expectedOutFlag); err != nil {
log.Fatalf("cannot open %q: %s", *expectedOutFlag, err)
}
fetchOutputTee = io.MultiWriter(os.Stdout, expectedOut)
defer expectedOut.Close()
} else {
fetchOutputTee = os.Stdout
}
}
runAlgos := make(map[string]bool)
if len(requestedAlgosFlag) > 0 {
for _, substr := range strings.Split(requestedAlgosFlag, ",") {
runAlgos[substr] = false
}
}
var algorithms []map[string]interface{}
for _, supportedAlgo := range supportedAlgos {
algoInterface, ok := supportedAlgo["algorithm"]
if !ok {
continue
}
algo, ok := algoInterface.(string)
if !ok {
continue
}
if _, ok := runAlgos[algo]; ok {
algorithms = append(algorithms, supportedAlgo)
runAlgos[algo] = true
}
}
for algo, recognised := range runAlgos {
if !recognised {
log.Fatalf("requested algorithm %q was not recognised", algo)
}
}
var config Config
if err := jsonFromFile(&config, *configFilename); err != nil {
log.Fatalf("Failed to load config file: %s", err)
}
var sessionTokensCacheDir string
if len(config.SessionTokensCache) > 0 {
sessionTokensCacheDir = config.SessionTokensCache
if strings.HasPrefix(sessionTokensCacheDir, "~/") {
home := os.Getenv("HOME")
if len(home) == 0 {
log.Fatal("~ used in config file but $HOME not set")
}
sessionTokensCacheDir = filepath.Join(home, sessionTokensCacheDir[2:])
}
}
if len(*uploadInputFile) > 0 {
uploadFromFile(*uploadInputFile, &config, sessionTokensCacheDir)
return
}
server, err := connect(&config, sessionTokensCacheDir)
if err != nil {
log.Fatal(err)
}
if err := server.Login(); err != nil {
log.Fatalf("failed to login: %s", err)
}
if len(requestedAlgosFlag) == 0 {
if interactiveModeSupported {
runInteractive(server, config)
} else {
log.Fatalf("no arguments given but interactive mode not supported")
}
return
}
requestBytes, err := json.Marshal(acvp.TestSession{
IsSample: true,
Publishable: false,
Algorithms: algorithms,
})
if err != nil {
log.Fatalf("Failed to serialise JSON: %s", err)
}
var result acvp.TestSession
if err := server.Post(&result, "acvp/v1/testSessions", requestBytes); err != nil {
log.Fatalf("Request to create test session failed: %s", err)
}
url := trimLeadingSlash(result.URL)
log.Printf("Created test session %q", url)
if token := result.AccessToken; len(token) > 0 {
server.PrefixTokens[url] = token
if len(sessionTokensCacheDir) > 0 {
os.WriteFile(filepath.Join(sessionTokensCacheDir, neturl.PathEscape(url))+".token", []byte(token), 0600)
}
}
log.Printf("Have vector sets %v", result.VectorSetURLs)
if len(*fetchFlag) > 0 {
io.WriteString(fetchOutputTee, "[\n")
json.NewEncoder(fetchOutputTee).Encode(vectorSetHeader{
URL: url,
VectorSetURLs: result.VectorSetURLs,
Time: time.Now().Format(time.RFC3339),
})
}
for _, setURL := range result.VectorSetURLs {
log.Printf("Fetching test vectors %q", setURL)
vectors, vectorsBytes, err := getVectorsWithRetry(server, trimLeadingSlash(setURL))
if err != nil {
log.Fatalf("Failed to fetch vector set %q: %s", setURL, err)
}
if len(*fetchFlag) > 0 {
os.Stdout.WriteString(",\n")
os.Stdout.Write(vectorsBytes)
}
if expectedOut != nil {
log.Printf("Fetching expected results")
_, expectedResultsBytes, err := getVectorsWithRetry(server, trimLeadingSlash(setURL)+"/expected")
if err != nil {
log.Fatalf("Failed to fetch expected results: %s", err)
}
expectedOut.WriteString(",")
expectedOut.Write(expectedResultsBytes)
}
if len(*fetchFlag) > 0 {
continue
}
replyGroups, err := middle.Process(vectors.Algo, vectorsBytes)
if err != nil {
log.Printf("Failed: %s", err)
log.Printf("Deleting test set")
server.Delete(url)
os.Exit(1)
}
headerBytes, err := json.Marshal(acvp.Vectors{
ID: vectors.ID,
Algo: vectors.Algo,
})
if err != nil {
log.Printf("Failed to marshal result: %s", err)
log.Printf("Deleting test set")
server.Delete(url)
os.Exit(1)
}
var resultBuf bytes.Buffer
resultBuf.Write(headerBytes[:len(headerBytes)-1])
resultBuf.WriteString(`,"testGroups":`)
replyBytes, err := json.Marshal(replyGroups)
if err != nil {
log.Printf("Failed to marshal result: %s", err)
log.Printf("Deleting test set")
server.Delete(url)
os.Exit(1)
}
resultBuf.Write(replyBytes)
resultBuf.WriteString("}")
if err := uploadResult(server, setURL, resultBuf.Bytes()); err != nil {
log.Printf("Deleting test set")
server.Delete(url)
log.Fatal(err)
}
}
if len(*fetchFlag) > 0 {
io.WriteString(fetchOutputTee, "]\n")
return
}
if ok, err := getResultsWithRetry(server, url); err != nil {
log.Fatal(err)
} else if !ok {
os.Exit(1)
}
}