blob: 1815aac8408d6a2a40adb0a3c662248bb3bebccc [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package hwsec
import (
"context"
"crypto"
"crypto/rsa"
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"strings"
"chromiumos/tast/common/hwsec"
"chromiumos/tast/errors"
hwseclocal "chromiumos/tast/local/hwsec"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: CertProvisionNoDatabase,
Desc: "Verifies cert provision is still working without attestation database",
Contacts: []string{"cylai@chromium.org", "cros-hwsec@google.com"},
SoftwareDeps: []string{"cert_provision", "tpm"},
})
}
func CertProvisionNoDatabase(ctx context.Context, s *testing.State) {
r := hwseclocal.NewCmdRunner()
helper, err := hwseclocal.NewFullHelper(ctx, r)
if err != nil {
s.Fatal("Helper creation error: ", err)
}
if err := helper.EnsureTPMIsReady(ctx, hwsec.DefaultTakingOwnershipTimeout); err != nil {
s.Fatal("Failed to ensure tpm readiness: ", err)
}
s.Log("TPM is ensured to be ready")
if err := helper.EnsureIsPreparedForEnrollment(ctx, hwsec.DefaultPreparationForEnrolmentTimeout); err != nil {
s.Fatal("Failed to prepare for enrollment: ", err)
}
s.Log("Attestation is prepared for enrollment")
const (
execName = "cert_provision_client"
provisionCmd = "--provision"
getCmd = "--get"
signCmd = "--sign"
defaultPCAOpt = "--pca=default"
defaultLabelOpt = "--label=cp9487"
defaultProfileOpt = "--profile=jetstream"
defaultDataFile = "/tmp/cpdata5487"
)
out, err := r.Run(
ctx,
execName,
provisionCmd,
defaultProfileOpt,
defaultPCAOpt,
defaultLabelOpt)
if err != nil {
s.Fatal("Failed to provision: ", err)
}
s.Log("Emulating Cleared attetation database")
fw := hwsec.NewFileWiper(r)
dCtrl := helper.DaemonController()
if err := func() (retErr error) {
if err := dCtrl.Stop(ctx, hwsec.AttestationDaemon); err != nil {
return errors.Wrap(err, "failed to stop attestationd")
}
defer func() {
if err := dCtrl.Start(ctx, hwsec.AttestationDaemon); err != nil && retErr == nil {
retErr = errors.Wrap(err, "failed to restart attestationd")
}
}()
return fw.Wipe(ctx, hwsec.AttestationDBPath)
}(); err != nil {
s.Fatal("Failed to wipe out attestation database: ", err)
}
defer func() {
s.Log("Restoring attestation DB")
if err := dCtrl.Stop(ctx, hwsec.AttestationDaemon); err != nil {
s.Error("Failed to stop attestationd: ", err)
} else {
defer func() {
if err := dCtrl.Start(ctx, hwsec.AttestationDaemon); err != nil {
s.Error("Failed to start attestationd: ", err)
}
}()
}
// Still tried to restore and the database even if the daemon is not stopped successfully.
if err := fw.Restore(ctx, hwsec.AttestationDBPath); err != nil {
s.Error("Failed to restore attestation database: ", err)
}
}()
out, err = r.Run(
ctx,
execName,
getCmd,
defaultLabelOpt,
"--include_chain")
if err != nil {
s.Fatal("Failed to get registered key: ", err)
}
block, _ := pem.Decode(out)
if block == nil {
s.Fatal("Failed to decode returned PEM")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
s.Fatal("Failed to parse cert: ", err)
}
rsaPublicKey := cert.PublicKey.(*rsa.PublicKey)
for _, mechanism := range []string{"sha1_rsa", "sha256_rsa"} {
s.Run(ctx, mechanism, func(ctx context.Context, s *testing.State) {
_, err := r.Run(ctx, "dd", "if=/dev/urandom", "bs=10", "count=1", "of="+defaultDataFile)
if err != nil {
s.Fatal("Failed to generate data: ", err)
}
data, err := r.Run(ctx, "cat", defaultDataFile)
if len(data) != 10 {
s.Fatal("Unexpected length of the data read (should be 10): ", len(data))
}
out, err := r.Run(ctx, execName, signCmd, defaultLabelOpt, "--in="+defaultDataFile, "--mechanism="+mechanism)
if err != nil {
s.Fatalf("Failed to sign %v: %v", string(out), err)
}
hashType, hashValue := func() (crypto.Hash, []byte) {
if mechanism == "sha1_rsa" {
h := sha1.Sum(data)
return crypto.SHA1, h[:]
}
h := sha256.Sum256(data)
return crypto.SHA256, h[:]
}()
trimmedOut := []byte(strings.TrimSpace(string(out)))
signature, err := hwsec.HexDecode(trimmedOut)
if err != nil {
s.Fatal("Failed to hex-decode the signature: ", err)
}
err = rsa.VerifyPKCS1v15(rsaPublicKey, hashType, hashValue, signature)
if err != nil {
s.Fatal("Failed to verify signature: ", err)
}
})
}
}