From 13dd306e69b26ab8b7aedcd6ed915df4b6672a01 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Tue, 27 Oct 2020 16:22:13 +0100 Subject: isolated chain and signature verification --- reqres.go | 41 +++++++++++------------------------------ x509.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/reqres.go b/reqres.go index a725363..e1f97ee 100644 --- a/reqres.go +++ b/reqres.go @@ -4,8 +4,6 @@ import ( "fmt" "strconv" - "crypto/ecdsa" - "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/json" @@ -186,50 +184,33 @@ func VerifyAddEntryRequest(ld *LogParameters, r AddEntryRequest) ([]byte, []byte leaf, err := tls.Marshal(item) if err != nil { return nil, nil, fmt.Errorf("failed tls marshaling StItem: %v", err) - } + } // leaf is the serialized data that should be added to the tree - certificate, err := base64.StdEncoding.DecodeString(r.Certificate) + c, err := base64.StdEncoding.DecodeString(r.Certificate) if err != nil { return nil, nil, fmt.Errorf("failed decoding certificate: %v", err) } - c, err := x509.ParseCertificate(certificate) + certificate, err := x509.ParseCertificate(c) if err != nil { return nil, nil, fmt.Errorf("failed decoding certificate: %v", err) - } - opts := x509.VerifyOptions{ - Roots: ld.AnchorPool, - } - chains, err := c.Verify(opts) + } // certificate is the end-entity certificate that signed leaf + + chain, err := VerifyChain(ld, certificate) if err != nil { return nil, nil, fmt.Errorf("chain verification failed: %v", err) - } - if len(chains) == 0 { - return nil, nil, fmt.Errorf("chain verification failed: no chain") - } - x509chain := chains[0] + } // chain is a valid path to some trust anchor signature, err := base64.StdEncoding.DecodeString(r.Signature) if err != nil { return nil, nil, fmt.Errorf("failed decoding signature: %v", err) } + if err := VerifySignature(leaf, signature, certificate); err != nil { + return nil, nil, fmt.Errorf("signature verification failed: %v", err) + } // signature is valid for certificate - var algo x509.SignatureAlgorithm - switch t := c.PublicKey.(type) { - case *rsa.PublicKey: - algo = x509.SHA256WithRSA - case *ecdsa.PublicKey: - algo = x509.ECDSAWithSHA256 - default: - return nil, nil, fmt.Errorf("unsupported public key algorithm: %v", t) - } - - if err := c.CheckSignature(algo, leaf, signature); err != nil { - return nil, nil, fmt.Errorf("invalid signature: %v", err) - } // TODO: update doc of what signature "is", i.e., w/e x509 does // TODO: doc in markdown/api.md what signature schemes we expect - - appendix, err := tls.Marshal(NewAppendix(x509chain, signature)) + appendix, err := tls.Marshal(NewAppendix(chain, signature)) if err != nil { return nil, nil, fmt.Errorf("failed tls marshaling appendix: %v", err) } diff --git a/x509.go b/x509.go index cdcd523..4e5a4d6 100644 --- a/x509.go +++ b/x509.go @@ -3,6 +3,8 @@ package stfe import ( "fmt" + "crypto/ecdsa" + "crypto/rsa" "crypto/x509" "encoding/pem" "io/ioutil" @@ -41,3 +43,36 @@ func LoadTrustAnchors(path string) ([]*x509.Certificate, *x509.CertPool, error) } return anchors, pool, nil } + +func VerifyChain(ld *LogParameters, certificate *x509.Certificate) ([]*x509.Certificate, error) { + opts := x509.VerifyOptions{ + Roots: ld.AnchorPool, + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, // TODO: move to ld + } // TODO: add intermediates + + chains, err := certificate.Verify(opts) + if err != nil { + return nil, fmt.Errorf("chain verification failed: %v", err) + } + if len(chains) == 0 { + return nil, fmt.Errorf("chain verification failed: no chain") + } + return chains[0], nil // if we found multiple paths just pick the first one +} + +func VerifySignature(leaf, signature []byte, certificate *x509.Certificate) error { + var algo x509.SignatureAlgorithm + switch t := certificate.PublicKey.(type) { + case *rsa.PublicKey: + algo = x509.SHA256WithRSA + case *ecdsa.PublicKey: + algo = x509.ECDSAWithSHA256 + default: + return fmt.Errorf("unsupported public key algorithm: %v", t) + } + + if err := certificate.CheckSignature(algo, leaf, signature); err != nil { + return fmt.Errorf("invalid signature: %v", err) + } + return nil +} -- cgit v1.2.3