Skip to content

Commit

Permalink
Add API for using crypto.Signer with SigningContext
Browse files Browse the repository at this point in the history
The main purpose of the pull request adds a `crypto.Signer` to `SigningContext`
to enable signing by an HSM. This change also enables signing with ECDSA
keypairs.

* Added `NewSigningContext` to construct a `SigningContext` that holds a
  `crypto.Signer` and the certificate chain and is mutually exclusive with
  `X509KeyStore`
* If the `SigningContext` has a non-nil `KeyStore`, it uses that instead to
  maintain backwards compatibility and not break existing code.
* Use `x509.Certificate`'s `CheckSignature` method instead of the RSA public
  key to support validation of ECDSA signatures
* Added constants and changed the maps slightly to support ECDSA signature
  methods.

Co-authored-by: charredlot <charredlot@gmail.com>
  • Loading branch information
Mike Wilson and charredlot committed Mar 6, 2023
1 parent b317f5f commit dcbd738
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 57 deletions.
123 changes: 100 additions & 23 deletions sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package dsig

import (
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
_ "crypto/sha1"
_ "crypto/sha256"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
Expand All @@ -15,11 +17,18 @@ import (
)

type SigningContext struct {
Hash crypto.Hash
Hash crypto.Hash

// This field will be nil and unused if the SigningContext is created with
// NewSigningContext
KeyStore X509KeyStore
IdAttribute string
Prefix string
Canonicalizer Canonicalizer

// KeyStore is mutually exclusive with signer and certs
signer crypto.Signer
certs [][]byte
}

func NewDefaultSigningContext(ks X509KeyStore) *SigningContext {
Expand All @@ -32,13 +41,54 @@ func NewDefaultSigningContext(ks X509KeyStore) *SigningContext {
}
}

// NewSigningContext creates a new signing context with the given signer and certificate chain.
// Note that e.g. rsa.PrivateKey implements the crypto.Signer interface.
// The certificate chain is a slice of ASN.1 DER-encoded X.509 certificates.
// A SigningContext created with this function should not use the KeyStore field.
// It will return error if passed a nil crypto.Signer
func NewSigningContext(signer crypto.Signer, certs [][]byte) (*SigningContext, error) {
if signer == nil {
return nil, errors.New("signer cannot be nil for NewSigningContext")
}
ctx := &SigningContext{
Hash: crypto.SHA256,
IdAttribute: DefaultIdAttr,
Prefix: DefaultPrefix,
Canonicalizer: MakeC14N11Canonicalizer(),

signer: signer,
certs: certs,
}
return ctx, nil
}

func (ctx *SigningContext) getPublicKeyAlgorithm() x509.PublicKeyAlgorithm {
if ctx.KeyStore != nil {
return x509.RSA
} else {
switch ctx.signer.Public().(type) {
case *ecdsa.PublicKey:
return x509.ECDSA
case *rsa.PublicKey:
return x509.RSA
}
}

return x509.UnknownPublicKeyAlgorithm
}

func (ctx *SigningContext) SetSignatureMethod(algorithmID string) error {
hash, ok := signatureMethodsByIdentifier[algorithmID]
info, ok := signatureMethodsByIdentifier[algorithmID]
if !ok {
return fmt.Errorf("Unknown SignatureMethod: %s", algorithmID)
return fmt.Errorf("unknown SignatureMethod: %s", algorithmID)
}

ctx.Hash = hash
algo := ctx.getPublicKeyAlgorithm()
if info.PublicKeyAlgorithm != algo {
return fmt.Errorf("SignatureMethod %s is incompatible with %s key", algorithmID, algo)
}

ctx.Hash = info.Hash

return nil
}
Expand All @@ -58,6 +108,46 @@ func (ctx *SigningContext) digest(el *etree.Element) ([]byte, error) {
return hash.Sum(nil), nil
}

func (ctx *SigningContext) signDigest(digest []byte) ([]byte, error) {
if ctx.KeyStore != nil {
key, _, err := ctx.KeyStore.GetKeyPair()
if err != nil {
return nil, err
}

rawSignature, err := rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest)
if err != nil {
return nil, err
}

return rawSignature, nil
} else {
rawSignature, err := ctx.signer.Sign(rand.Reader, digest, ctx.Hash)
if err != nil {
return nil, err
}

return rawSignature, nil
}
}

func (ctx *SigningContext) getCerts() ([][]byte, error) {
if ctx.KeyStore != nil {
if cs, ok := ctx.KeyStore.(X509ChainStore); ok {
return cs.GetChain()
}

_, cert, err := ctx.KeyStore.GetKeyPair()
if err != nil {
return nil, err
}

return [][]byte{cert}, nil
} else {
return ctx.certs, nil
}
}

func (ctx *SigningContext) constructSignedInfo(el *etree.Element, enveloped bool) (*etree.Element, error) {
digestAlgorithmIdentifier := ctx.GetDigestAlgorithmIdentifier()
if digestAlgorithmIdentifier == "" {
Expand Down Expand Up @@ -97,7 +187,6 @@ func (ctx *SigningContext) constructSignedInfo(el *etree.Element, enveloped bool
reference.CreateAttr(URIAttr, "#"+dataId)
}


// /SignedInfo/Reference/Transforms
transforms := ctx.createNamespacedElement(reference, TransformsTag)
if enveloped {
Expand Down Expand Up @@ -172,20 +261,12 @@ func (ctx *SigningContext) ConstructSignature(el *etree.Element, enveloped bool)
return nil, err
}

key, cert, err := ctx.KeyStore.GetKeyPair()
rawSignature, err := ctx.signDigest(digest)
if err != nil {
return nil, err
}

certs := [][]byte{cert}
if cs, ok := ctx.KeyStore.(X509ChainStore); ok {
certs, err = cs.GetChain()
if err != nil {
return nil, err
}
}

rawSignature, err := rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest)
certs, err := ctx.getCerts()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -222,7 +303,9 @@ func (ctx *SigningContext) SignEnveloped(el *etree.Element) (*etree.Element, err
}

func (ctx *SigningContext) GetSignatureMethodIdentifier() string {
if ident, ok := signatureMethodIdentifiers[ctx.Hash]; ok {
algo := ctx.getPublicKeyAlgorithm()

if ident, ok := signatureMethodIdentifiers[algo][ctx.Hash]; ok {
return ident
}
return ""
Expand All @@ -247,11 +330,5 @@ func (ctx *SigningContext) SignString(content string) ([]byte, error) {
}
digest := hash.Sum(nil)

var signature []byte
if key, _, err := ctx.KeyStore.GetKeyPair(); err != nil {
return nil, fmt.Errorf("unable to fetch key for signing: %v", err)
} else if signature, err = rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest); err != nil {
return nil, fmt.Errorf("error signing: %v", err)
}
return signature, nil
return ctx.signDigest(digest)
}
51 changes: 48 additions & 3 deletions sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dsig

import (
"crypto"
"crypto/tls"
"encoding/base64"
"testing"

Expand All @@ -12,14 +13,24 @@ import (
func TestSign(t *testing.T) {
randomKeyStore := RandomKeyStoreForTest()
ctx := NewDefaultSigningContext(randomKeyStore)
testSignWithContext(t, ctx, RSASHA256SignatureMethod, crypto.SHA256)
}

func TestNewSigningContext(t *testing.T) {
randomKeyStore := RandomKeyStoreForTest().(*MemoryX509KeyStore)
ctx, err := NewSigningContext(randomKeyStore.privateKey, [][]byte{randomKeyStore.cert})
require.NoError(t, err)
testSignWithContext(t, ctx, RSASHA256SignatureMethod, crypto.SHA256)
}

func testSignWithContext(t *testing.T, ctx *SigningContext, sigMethodID string, digestAlgo crypto.Hash) {
authnRequest := &etree.Element{
Space: "samlp",
Tag: "AuthnRequest",
}
id := "_97e34c50-65ec-4132-8b39-02933960a96a"
authnRequest.CreateAttr("ID", id)
hash := crypto.SHA256.New()
hash := digestAlgo.New()
canonicalized, err := ctx.Canonicalizer.Canonicalize(authnRequest)
require.NoError(t, err)

Expand Down Expand Up @@ -49,7 +60,7 @@ func TestSign(t *testing.T) {

signatureMethodAttr := signatureMethodElement.SelectAttr(AlgorithmAttr)
require.NotEmpty(t, signatureMethodAttr)
require.Equal(t, "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", signatureMethodAttr.Value)
require.Equal(t, sigMethodID, signatureMethodAttr.Value)

referenceElement := signedInfo.FindElement("//" + ReferenceTag)
require.NotEmpty(t, referenceElement)
Expand All @@ -73,7 +84,7 @@ func TestSign(t *testing.T) {

digestMethodAttr := digestMethodElement.SelectAttr(AlgorithmAttr)
require.NotEmpty(t, digestMethodElement)
require.Equal(t, "http://www.w3.org/2001/04/xmlenc#sha256", digestMethodAttr.Value)
require.Equal(t, digestAlgorithmIdentifiers[digestAlgo], digestMethodAttr.Value)

digestValueElement := referenceElement.FindElement("//" + DigestValueTag)
require.NotEmpty(t, digestValueElement)
Expand Down Expand Up @@ -126,3 +137,37 @@ func TestSignNonDefaultID(t *testing.T) {
refURI := ref.SelectAttrValue("URI", "")
require.Equal(t, refURI, "#"+id)
}

func TestIncompatibleSignatureMethods(t *testing.T) {
// RSA
randomKeyStore := RandomKeyStoreForTest().(*MemoryX509KeyStore)
ctx, err := NewSigningContext(randomKeyStore.privateKey, [][]byte{randomKeyStore.cert})
require.NoError(t, err)

err = ctx.SetSignatureMethod(ECDSASHA512SignatureMethod)
require.Error(t, err)

// ECDSA
testECDSACert, err := tls.X509KeyPair([]byte(ecdsaCert), []byte(ecdsaKey))
require.NoError(t, err)

ctx, err = NewSigningContext(testECDSACert.PrivateKey.(crypto.Signer), testECDSACert.Certificate)
require.NoError(t, err)

err = ctx.SetSignatureMethod(RSASHA1SignatureMethod)
require.Error(t, err)
}

func TestSignWithECDSA(t *testing.T) {
cert, err := tls.X509KeyPair([]byte(ecdsaCert), []byte(ecdsaKey))
require.NoError(t, err)

ctx, err := NewSigningContext(cert.PrivateKey.(crypto.Signer), cert.Certificate)
require.NoError(t, err)

method := ECDSASHA512SignatureMethod
err = ctx.SetSignatureMethod(method)
require.NoError(t, err)

testSignWithContext(t, ctx, method, crypto.SHA512)
}
19 changes: 2 additions & 17 deletions validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dsig

import (
"bytes"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"errors"
Expand Down Expand Up @@ -213,26 +212,12 @@ func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicaliz
return err
}

signatureAlgorithm, ok := signatureMethodsByIdentifier[signatureMethodId]
algo, ok := x509SignatureAlgorithmByIdentifier[signatureMethodId]
if !ok {
return errors.New("Unknown signature method: " + signatureMethodId)
}

hash := signatureAlgorithm.New()
_, err = hash.Write(canonical)
if err != nil {
return err
}

hashed := hash.Sum(nil)

pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
if !ok {
return errors.New("Invalid public key")
}

// Verify that the private key matching the public key from the cert was what was used to sign the 'SignedInfo' and produce the 'SignatureValue'
err = rsa.VerifyPKCS1v15(pubKey, signatureAlgorithm, hashed[:], decodedSignature)
err = cert.CheckSignature(algo, canonical, decodedSignature)
if err != nil {
return err
}
Expand Down
46 changes: 44 additions & 2 deletions validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,32 @@ yy7YHlSiVX13QH2XTu/iQQ==
-----END CERTIFICATE-----
`

const ecdsaResponse = `<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id-e65dcbd76bd33f51c51137855d499382ffcbd235" Version="2.0" IssueInstant="2019-06-14T21:16:16.206Z"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://localhost/saml/acs/</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"/><ds:Reference URI="#id-e65dcbd76bd33f51c51137855d499382ffcbd235"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>Uh15pBqpaLb8KW9EnUCSsw1D3UN6IE7cM6c69fwy1xQ=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>MEUCIAwuDhyvbhNE7vfS9oqsGwdao/E8EJSK1mQ8gIEIIOQBAiEAud5l0TQru0m291/XzWvdBJ71HN/hOknOnKXqM7OwXrU=</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIB3jCCAYSgAwIBAgITC3mzvAn7vitNgC2KTnea8hlp8jAKBggqhkjOPQQDAjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE5MDYxMzAwNTYwMVoXDTIxMDYxMjAwNTYwMVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEIa9GeZw9TVMAv7Vnn3bz0DdQstQTIHkSnYfKw6QObxRZJoWvDRcvv2zblCki5FuqTbYqUNeDIQEsKwTJRHUCKjUzBRMB0GA1UdDgQWBBRDic4JRcFytcfX1QkFlsOJVUdrTzAfBgNVHSMEGDAWgBRDic4JRcFytcfX1QkFlsOJVUdrTzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDF2He80OqZJCe8Fjo0BlS5UsRJ3tChy/ZbmkE2DUaFjgIgKpLzRwr21VdekDagOpZj8ENzJ9YC5w+BwffTRwfkyLE=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="beepboopmeow" IssueInstant="2019-06-14T21:16:16.206Z" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">urn:extrahop:saml:hopcloud:ra:idp</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"/><ds:Reference URI="#beepboopmeow"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>FfMcWntKHiIB8bpyFayq1nK5wtcCHMpCUnowv7/0dBQ=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>MEQCIFXVoJmVBLb+zJKDwnIBUA+Mdp0ww0689pvIDPktROS1AiAimmnSUjzMMflVUJvngeyJta33wVMMObIxcEDNesco5A==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIB3jCCAYSgAwIBAgITC3mzvAn7vitNgC2KTnea8hlp8jAKBggqhkjOPQQDAjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE5MDYxMzAwNTYwMVoXDTIxMDYxMjAwNTYwMVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEIa9GeZw9TVMAv7Vnn3bz0DdQstQTIHkSnYfKw6QObxRZJoWvDRcvv2zblCki5FuqTbYqUNeDIQEsKwTJRHUCKjUzBRMB0GA1UdDgQWBBRDic4JRcFytcfX1QkFlsOJVUdrTzAfBgNVHSMEGDAWgBRDic4JRcFytcfX1QkFlsOJVUdrTzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDF2He80OqZJCe8Fjo0BlS5UsRJ3tChy/ZbmkE2DUaFjgIgKpLzRwr21VdekDagOpZj8ENzJ9YC5w+BwffTRwfkyLE=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">woof</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2019-06-14T21:17:46.206Z"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2019-06-14T21:13:16.206Z" NotOnOrAfter="2019-06-14T21:17:46.206Z"><saml:AudienceRestriction><saml:Audience></saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2019-06-14T21:16:16.206Z" SessionIndex="beepboopmeow"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">reserved</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:2.5.4.4" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">reserved</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">boop@example.com</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>`

const ecdsaCert = `
-----BEGIN CERTIFICATE-----
MIIB3jCCAYSgAwIBAgITC3mzvAn7vitNgC2KTnea8hlp8jAKBggqhkjOPQQDAjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE5MDYxMzAwNTYwMVoXDTIxMDYxMjAw
NTYwMVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNV
BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABEIa9GeZw9TVMAv7Vnn3bz0DdQstQTIHkSnYfKw6QObxRZJoWvDRcvv2
zblCki5FuqTbYqUNeDIQEsKwTJRHUCKjUzBRMB0GA1UdDgQWBBRDic4JRcFytcfX
1QkFlsOJVUdrTzAfBgNVHSMEGDAWgBRDic4JRcFytcfX1QkFlsOJVUdrTzAPBgNV
HRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDF2He80OqZJCe8Fjo0BlS5
UsRJ3tChy/ZbmkE2DUaFjgIgKpLzRwr21VdekDagOpZj8ENzJ9YC5w+BwffTRwfk
yLE=
-----END CERTIFICATE-----
`

const ecdsaKey = `
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEILnLofyDaFeGyDutTFYuWY0u5IVmny1spzfJbCixceI7oAoGCCqGSM49
AwEHoUQDQgAEQhr0Z5nD1NUwC/tWefdvPQN1Cy1BMgeRKdh8rDpA5vFFkmha8NFy
+/bNuUKSLkW6pNtipQ14MhASwrBMlEdQIg==
-----END EC PRIVATE KEY-----
`

func TestDigest(t *testing.T) {
canonicalizer := MakeC14N10ExclusiveCanonicalizerWithPrefixList("")
doc := etree.NewDocument()
Expand Down Expand Up @@ -191,20 +217,36 @@ func TestValidateWithEmptySignatureReference(t *testing.T) {
require.NotEmpty(t, reference)
require.Empty(t, reference.SelectAttr(URIAttr).Value)

block, _ := pem.Decode([]byte(oktaCert))
testValidateDoc(t, doc, oktaCert)
}

func testValidateDoc(t *testing.T, doc *etree.Document, certPEM string) {
block, _ := pem.Decode([]byte(certPEM))
cert, err := x509.ParseCertificate(block.Bytes)
require.NoError(t, err, "couldn't parse okta cert pem block")
require.NoError(t, err, "couldn't parse cert pem block")

certStore := MemoryX509CertificateStore{
Roots: []*x509.Certificate{cert},
}
vc := NewDefaultValidationContext(&certStore)
vc.Clock = NewFakeClockAt(cert.NotBefore)

el, err := vc.Validate(doc.Root())
require.NoError(t, err)
require.NotEmpty(t, el)
}

func TestValidateECDSA(t *testing.T) {
doc := etree.NewDocument()
err := doc.ReadFromBytes([]byte(ecdsaResponse))
require.NoError(t, err)

sig := doc.FindElement("//" + SignatureTag)
require.NotEmpty(t, sig)

testValidateDoc(t, doc, ecdsaCert)
}

const (
validateCert = `
-----BEGIN CERTIFICATE-----
Expand Down
Loading

0 comments on commit dcbd738

Please sign in to comment.