From 048f354b2a4085ef59b40c904fc8b8e1c318f873 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Mon, 5 Oct 2020 15:48:12 -0700 Subject: [PATCH] acvp: handle more private key formats. This change adds a config parameter PrivateKeyFile (to replace PrivateKeyDERFile, although that still exists) because taking PKCS#1 DER is a little odd for people. Also probe for PEM/DER and PKCS#1/8 automatically to try and work with whatever private key the user has. Change-Id: I0f4efcd79528cfb26f791e9ee8c5141fc6a93723 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/43344 Reviewed-by: David Benjamin --- util/fipstools/acvp/ACVP.md | 4 ++-- util/fipstools/acvp/acvptool/acvp.go | 34 ++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/util/fipstools/acvp/ACVP.md b/util/fipstools/acvp/ACVP.md index ddae4ed41..71501de7d 100644 --- a/util/fipstools/acvp/ACVP.md +++ b/util/fipstools/acvp/ACVP.md @@ -13,14 +13,14 @@ Configuration is done via a `config.json` file in the current working directory. { "ACVPServer": "https://demo.acvts.nist.gov/", "CertPEMFile": "certificate_from_nist.pem", - "PrivateKeyDERFile": "your_private_key.key", + "PrivateKeyFile": "your_private_key.key", "TOTPSecret": "", "SessionTokensCache": "~/.cache/acvp-session-tokens", "LogFile": "log" } ``` -NIST's ACVP servers use both TLS client certificates and TOTP for authentication. When registering with NIST, they'll sign a CSR and return a certificate in PEM format, which is pointed to be `CertPEMFile`. The corresponding PKCS#1, DER-encoded private key is expected in `PrivateKeyDERFile`. Lastly, NIST will provide a file that contains the base64-encoded TOTP seed, which must be pasted in as the value of `TOTPSecret`. +NIST's ACVP servers use both TLS client certificates and TOTP for authentication. When registering with NIST, they'll sign a CSR and return a certificate in PEM format, which is pointed to be `CertPEMFile`. The corresponding private key is expected in `PrivateKeyFile`. Lastly, NIST will provide a file that contains the base64-encoded TOTP seed, which must be pasted in as the value of `TOTPSecret`. NIST's ACVP server provides special access tokens for each test session and test sessions can _only_ be accessed via those tokens. The reasoning behind this is unclear but this client can, optionally, keep records of these access tokens in the directory named by `SessionTokensCache`. If that directory name begins with `~/` then that prefix will be replaced with the value of `$HOME`. diff --git a/util/fipstools/acvp/acvptool/acvp.go b/util/fipstools/acvp/acvptool/acvp.go index feebed504..bc8b0d87e 100644 --- a/util/fipstools/acvp/acvptool/acvp.go +++ b/util/fipstools/acvp/acvptool/acvp.go @@ -17,6 +17,7 @@ package main import ( "bufio" "bytes" + "crypto" "crypto/hmac" "crypto/sha256" "crypto/x509" @@ -51,6 +52,7 @@ var ( type Config struct { CertPEMFile string + PrivateKeyFile string PrivateKeyDERFile string TOTPSecret string ACVPServer string @@ -281,17 +283,35 @@ func main() { block, _ := pem.Decode(certPEM) certDER := block.Bytes - if len(config.PrivateKeyDERFile) == 0 { - log.Fatal("Config file missing PrivateKeyDERFile") + if len(config.PrivateKeyDERFile) == 0 && len(config.PrivateKeyFile) == 0 { + log.Fatal("Config file missing PrivateKeyDERFile and PrivateKeyFile") } - keyDER, err := ioutil.ReadFile(config.PrivateKeyDERFile) - if err != nil { - log.Fatalf("failed to read private key from %q: %s", config.PrivateKeyDERFile, err) + if len(config.PrivateKeyDERFile) != 0 && len(config.PrivateKeyFile) != 0 { + log.Fatal("Config file has both PrivateKeyDERFile and PrivateKeyFile. Can only have one.") + } + privateKeyFile := config.PrivateKeyDERFile + if len(config.PrivateKeyFile) > 0 { + privateKeyFile = config.PrivateKeyFile } - certKey, err := x509.ParsePKCS1PrivateKey(keyDER) + keyBytes, err := ioutil.ReadFile(privateKeyFile) if err != nil { - log.Fatalf("failed to parse private key from %q: %s", config.PrivateKeyDERFile, err) + log.Fatalf("failed to read private key from %q: %s", privateKeyFile, err) + } + + var keyDER []byte + pemBlock, _ := pem.Decode(keyBytes) + if pemBlock != nil { + keyDER = pemBlock.Bytes + } else { + keyDER = keyBytes + } + + var certKey crypto.PrivateKey + if certKey, err = x509.ParsePKCS1PrivateKey(keyDER); err != nil { + if certKey, err = x509.ParsePKCS8PrivateKey(keyDER); err != nil { + log.Fatalf("failed to parse private key from %q: %s", privateKeyFile, err) + } } var middle Middle